Skip to content
Snippets Groups Projects
Unverified Commit f005b1a9 authored by Jacki's avatar Jacki
Browse files

Implement slang compiler


Signed-off-by: default avatarJacki <jacki@thejackimonster.de>
parent a7496fd7
No related branches found
No related tags found
1 merge request!115Resolve "Slang Compiler"
...@@ -84,11 +84,11 @@ namespace vkcv::shader { ...@@ -84,11 +84,11 @@ namespace vkcv::shader {
* @param[in] includePath Include path for shaders * @param[in] includePath Include path for shaders
* @param[in] update Flag to update shaders during runtime * @param[in] update Flag to update shaders during runtime
*/ */
virtual void compile(ShaderStage shaderStage, void compile(ShaderStage shaderStage,
const std::filesystem::path& shaderPath, const std::filesystem::path& shaderPath,
const ShaderCompiledFunction& compiled, const ShaderCompiledFunction& compiled,
const std::filesystem::path& includePath, const std::filesystem::path& includePath = "",
bool update) = 0; bool update = false);
/** /**
* Compile a shader program from a specific map of given file paths for * Compile a shader program from a specific map of given file paths for
......
#pragma once #pragma once
#include <filesystem>
#include <vkcv/ShaderStage.hpp> #include <vkcv/ShaderStage.hpp>
#include "Compiler.hpp" #include "Compiler.hpp"
...@@ -57,23 +55,6 @@ namespace vkcv::shader { ...@@ -57,23 +55,6 @@ namespace vkcv::shader {
*/ */
GlslangCompiler& operator=(GlslangCompiler&& other) = default; GlslangCompiler& operator=(GlslangCompiler&& other) = default;
/**
* Compile a shader from a specific file path for a target stage with
* a custom shader include path and an event function called if the
* compilation completes.
*
* @param[in] shaderStage Shader pipeline stage
* @param[in] shaderPath Filepath of shader
* @param[in] compiled Shader compilation event
* @param[in] includePath Include path for shaders
* @param[in] update Flag to update shaders during runtime
*/
void compile(ShaderStage shaderStage,
const std::filesystem::path& shaderPath,
const ShaderCompiledFunction& compiled,
const std::filesystem::path& includePath = "",
bool update = false) override;
}; };
/** @} */ /** @} */
......
...@@ -57,23 +57,6 @@ namespace vkcv::shader { ...@@ -57,23 +57,6 @@ namespace vkcv::shader {
*/ */
ShadyCompiler& operator=(ShadyCompiler&& other) = default; ShadyCompiler& operator=(ShadyCompiler&& other) = default;
/**
* Compile a shader from a specific file path for a target stage with
* a custom shader include path and an event function called if the
* compilation completes.
*
* @param[in] shaderStage Shader pipeline stage
* @param[in] shaderPath Filepath of shader
* @param[in] compiled Shader compilation event
* @param[in] includePath Include path for shaders
* @param[in] update Flag to update shaders during runtime
*/
void compile(ShaderStage shaderStage,
const std::filesystem::path& shaderPath,
const ShaderCompiledFunction& compiled,
const std::filesystem::path& includePath = "",
bool update = false) override;
}; };
/** @} */ /** @} */
......
...@@ -12,15 +12,27 @@ namespace vkcv::shader { ...@@ -12,15 +12,27 @@ namespace vkcv::shader {
* @{ * @{
*/ */
enum class SlangCompileProfile {
GLSL,
HLSL,
SPIRV,
UNKNOWN
};
/** /**
* An abstract class to handle Slang runtime shader compilation. * An abstract class to handle Slang runtime shader compilation.
*/ */
class SlangCompiler : public Compiler { class SlangCompiler : public Compiler {
private:
SlangCompileProfile m_profile;
public: public:
/** /**
* The constructor of a runtime Slang shader compiler instance. * The constructor of a runtime Slang shader compiler instance.
*
* @param[in] profile Compile profile (optional)
*/ */
SlangCompiler(); SlangCompiler(SlangCompileProfile profile = SlangCompileProfile::UNKNOWN);
/** /**
* The copy-constructor of a runtime Slang shader compiler instance. * The copy-constructor of a runtime Slang shader compiler instance.
...@@ -56,23 +68,21 @@ namespace vkcv::shader { ...@@ -56,23 +68,21 @@ namespace vkcv::shader {
* @return Reference to this instance * @return Reference to this instance
*/ */
SlangCompiler& operator=(SlangCompiler&& other) = default; SlangCompiler& operator=(SlangCompiler&& other) = default;
/** /**
* Compile a shader from a specific file path for a target stage with * Compile a shader from source for a target stage with a custom shader
* a custom shader include path and an event function called if the * include path and an event function called if the compilation completes.
* compilation completes. *
* * @param[in] shaderStage Shader pipeline stage
* @param[in] shaderStage Shader pipeline stage * @param[in] shaderSource Source of shader
* @param[in] shaderPath Filepath of shader * @param[in] compiled Shader compilation event
* @param[in] compiled Shader compilation event * @param[in] includePath Include path for shaders
* @param[in] includePath Include path for shaders * @return Result if the compilation succeeds
* @param[in] update Flag to update shaders during runtime */
*/ bool compileSource(ShaderStage shaderStage,
void compile(ShaderStage shaderStage, const std::string& shaderSource,
const std::filesystem::path& shaderPath, const ShaderCompiledFunction& compiled,
const ShaderCompiledFunction& compiled, const std::filesystem::path& includePath) override;
const std::filesystem::path& includePath = "",
bool update = false) override;
}; };
......
...@@ -41,6 +41,33 @@ namespace vkcv::shader { ...@@ -41,6 +41,33 @@ namespace vkcv::shader {
}, directory }, directory
); );
} }
void Compiler::compile(ShaderStage shaderStage,
const std::filesystem::path &shaderPath,
const ShaderCompiledFunction &compiled,
const std::filesystem::path &includePath,
bool update) {
std::string shaderCode;
bool result = readTextFromFile(shaderPath, shaderCode);
if (!result) {
vkcv_log(LogLevel::ERROR, "Loading shader failed: (%s)", shaderPath.string().c_str());
}
if (!includePath.empty()) {
result = compileSource(shaderStage, shaderCode, compiled, includePath);
} else {
result = compileSource(shaderStage, shaderCode, compiled, shaderPath.parent_path());
}
if (!result) {
vkcv_log(LogLevel::ERROR, "Shader compilation failed: (%s)", shaderPath.string().c_str());
}
if (update) {
// TODO: Shader hot compilation during runtime
}
}
void Compiler::compileProgram(ShaderProgram& program, void Compiler::compileProgram(ShaderProgram& program,
const Dictionary<ShaderStage, const std::filesystem::path>& stages, const Dictionary<ShaderStage, const std::filesystem::path>& stages,
......
...@@ -36,31 +36,4 @@ namespace vkcv::shader { ...@@ -36,31 +36,4 @@ namespace vkcv::shader {
return *this; return *this;
} }
void GlslangCompiler::compile(ShaderStage shaderStage,
const std::filesystem::path &shaderPath,
const ShaderCompiledFunction &compiled,
const std::filesystem::path &includePath,
bool update) {
std::string shaderCode;
bool result = readTextFromFile(shaderPath, shaderCode);
if (!result) {
vkcv_log(LogLevel::ERROR, "Loading shader failed: (%s)", shaderPath.string().c_str());
}
if (!includePath.empty()) {
result = compileSource(shaderStage, shaderCode, compiled, includePath);
} else {
result = compileSource(shaderStage, shaderCode, compiled, shaderPath.parent_path());
}
if (!result) {
vkcv_log(LogLevel::ERROR, "Shader compilation failed: (%s)", shaderPath.string().c_str());
}
if (update) {
// TODO: Shader hot compilation during runtime
}
}
} }
...@@ -9,31 +9,4 @@ namespace vkcv::shader { ...@@ -9,31 +9,4 @@ namespace vkcv::shader {
ShadyCompiler::ShadyCompiler() ShadyCompiler::ShadyCompiler()
: Compiler() {} : Compiler() {}
void ShadyCompiler::compile(ShaderStage shaderStage,
const std::filesystem::path &shaderPath,
const ShaderCompiledFunction &compiled,
const std::filesystem::path &includePath,
bool update) {
std::string shaderCode;
bool result = readTextFromFile(shaderPath, shaderCode);
if (!result) {
vkcv_log(LogLevel::ERROR, "Loading shader failed: (%s)", shaderPath.string().c_str());
}
if (!includePath.empty()) {
result = compileSource(shaderStage, shaderCode, compiled, includePath);
} else {
result = compileSource(shaderStage, shaderCode, compiled, shaderPath.parent_path());
}
if (!result) {
vkcv_log(LogLevel::ERROR, "Shader compilation failed: (%s)", shaderPath.string().c_str());
}
if (update) {
// TODO: Shader hot compilation during runtime
}
}
} }
#include "vkcv/shader/SlangCompiler.hpp" #include "vkcv/shader/SlangCompiler.hpp"
#include <cstdint>
#include <vkcv/File.hpp> #include <vkcv/File.hpp>
#include <vkcv/Logger.hpp> #include <vkcv/Logger.hpp>
#include <slang.h> #include <slang.h>
#include <slang-com-ptr.h>
#include <slang-com-helper.h>
#include <vkcv/ShaderStage.hpp>
namespace vkcv::shader { namespace vkcv::shader {
static uint32_t s_CompilerCount = 0; static uint32_t s_CompilerCount = 0;
static slang::IGlobalSession* s_GlobalSession = nullptr; static Slang::ComPtr<slang::IGlobalSession> s_GlobalSession;
SlangCompiler::SlangCompiler() : Compiler() { SlangCompiler::SlangCompiler(SlangCompileProfile profile)
: Compiler(), m_profile(profile) {
if (s_CompilerCount == 0) { if (s_CompilerCount == 0) {
slang::createGlobalSession(&s_GlobalSession); slang::createGlobalSession(s_GlobalSession.writeRef());
} }
s_CompilerCount++; s_CompilerCount++;
} }
SlangCompiler::SlangCompiler(const SlangCompiler &other) : Compiler(other) { SlangCompiler::SlangCompiler(const SlangCompiler &other)
: Compiler(other), m_profile(other.m_profile) {
s_CompilerCount++; s_CompilerCount++;
} }
SlangCompiler::~SlangCompiler() { SlangCompiler::~SlangCompiler() {
s_CompilerCount--; s_CompilerCount--;
if ((s_CompilerCount == 0) && (s_GlobalSession != nullptr)) {
spDestroySession(s_GlobalSession);
s_GlobalSession = nullptr;
}
} }
SlangCompiler &SlangCompiler::operator=(const SlangCompiler &other) { SlangCompiler &SlangCompiler::operator=(const SlangCompiler &other) {
m_profile = other.m_profile;
s_CompilerCount++; s_CompilerCount++;
return *this; return *this;
} }
void SlangCompiler::compile(ShaderStage shaderStage, constexpr SlangStage findShaderLanguage(ShaderStage shaderStage) {
const std::filesystem::path &shaderPath, switch (shaderStage) {
const ShaderCompiledFunction &compiled, case ShaderStage::VERTEX:
const std::filesystem::path &includePath, return SlangStage::SLANG_STAGE_VERTEX;
bool update) { case ShaderStage::TESS_CONTROL:
std::string shaderCode; return SlangStage::SLANG_STAGE_HULL;
bool result = readTextFromFile(shaderPath, shaderCode); case ShaderStage::TESS_EVAL:
return SlangStage::SLANG_STAGE_DOMAIN;
if (!result) { case ShaderStage::GEOMETRY:
vkcv_log(LogLevel::ERROR, "Loading shader failed: (%s)", shaderPath.string().c_str()); return SlangStage::SLANG_STAGE_GEOMETRY;
case ShaderStage::FRAGMENT:
return SlangStage::SLANG_STAGE_FRAGMENT;
case ShaderStage::COMPUTE:
return SlangStage::SLANG_STAGE_COMPUTE;
case ShaderStage::TASK:
return SlangStage::SLANG_STAGE_AMPLIFICATION;
case ShaderStage::MESH:
return SlangStage::SLANG_STAGE_MESH;
case ShaderStage::RAY_GEN:
return SlangStage::SLANG_STAGE_RAY_GENERATION;
case ShaderStage::RAY_CLOSEST_HIT:
return SlangStage::SLANG_STAGE_CLOSEST_HIT;
case ShaderStage::RAY_MISS:
return SlangStage::SLANG_STAGE_MISS;
case ShaderStage::RAY_INTERSECTION:
return SlangStage::SLANG_STAGE_INTERSECTION;
case ShaderStage::RAY_ANY_HIT:
return SlangStage::SLANG_STAGE_ANY_HIT;
case ShaderStage::RAY_CALLABLE:
return SlangStage::SLANG_STAGE_CALLABLE;
default:
return SlangStage::SLANG_STAGE_NONE;
} }
}
if (!includePath.empty()) {
result = compileSource(shaderStage, shaderCode, compiled, includePath); bool SlangCompiler::compileSource(ShaderStage shaderStage,
} else { const std::string& shaderSource,
result = compileSource(shaderStage, shaderCode, compiled, shaderPath.parent_path()); const ShaderCompiledFunction& compiled,
const std::filesystem::path& includePath) {
slang::SessionDesc sessionDesc = {};
slang::TargetDesc targetDesc = {};
targetDesc.format = SLANG_SPIRV;
switch (m_profile) {
case SlangCompileProfile::GLSL:
targetDesc.profile = s_GlobalSession->findProfile("glsl_460");
sessionDesc.defaultMatrixLayoutMode = SLANG_MATRIX_LAYOUT_COLUMN_MAJOR;
break;
case SlangCompileProfile::HLSL:
targetDesc.profile = s_GlobalSession->findProfile("sm_5_0");
sessionDesc.defaultMatrixLayoutMode = SLANG_MATRIX_LAYOUT_ROW_MAJOR;
break;
case SlangCompileProfile::SPIRV:
targetDesc.profile = s_GlobalSession->findProfile("spirv_1_5");
targetDesc.flags = SLANG_TARGET_FLAG_GENERATE_SPIRV_DIRECTLY;
break;
default:
break;
} }
if (!result) { sessionDesc.targets = &targetDesc;
vkcv_log(LogLevel::ERROR, "Shader compilation failed: (%s)", shaderPath.string().c_str()); sessionDesc.targetCount = 1;
const char *searchPath = includePath.c_str();
sessionDesc.searchPaths = &searchPath;
sessionDesc.searchPathCount = 1;
Slang::ComPtr<slang::ISession> session;
if (SLANG_FAILED(s_GlobalSession->createSession(sessionDesc, session.writeRef()))) {
vkcv_log(LogLevel::ERROR, "Compiler session could not be created");
return false;
}
Slang::ComPtr<slang::ICompileRequest> request;
if (SLANG_FAILED(session->createCompileRequest(request.writeRef()))) {
vkcv_log(LogLevel::ERROR, "Compilation request could not be created");
return false;
}
const int entryPoint = request->addEntryPoint(
0, "main", findShaderLanguage(shaderStage)
);
if (SLANG_FAILED(request->compile())) {
vkcv_log(LogLevel::ERROR, "Compilation process failed");
return false;
}
size_t size;
const void *code = request->getEntryPointCode(entryPoint, &size);
if ((size <= 0) || (!code)) {
vkcv_log(LogLevel::ERROR, "Entry point could not be found");
return false;
}
std::vector<uint32_t> spirv;
spirv.resize(size / sizeof(uint32_t));
memcpy(spirv.data(), code, spirv.size() * sizeof(uint32_t));
const std::filesystem::path tmp_path = generateTemporaryFilePath();
if (!writeBinaryToFile(tmp_path, spirv)) {
vkcv_log(LogLevel::ERROR, "Spir-V could not be written to disk");
return false;
} }
if (update) { if (compiled) {
// TODO: Shader hot compilation during runtime compiled(shaderStage, tmp_path);
} }
std::filesystem::remove(tmp_path);
return true;
} }
} }
...@@ -14,15 +14,15 @@ namespace vkcv::shader { ...@@ -14,15 +14,15 @@ namespace vkcv::shader {
: ShadyCompiler(), m_target(target) {} : ShadyCompiler(), m_target(target) {}
static bool shadyCompileModule(Module* module, static bool shadyCompileModule(Module* module,
ShaderStage shaderStage, ShaderStage shaderStage,
const std::string& shaderSource, const std::string& shaderSource,
const ShaderCompiledFunction &compiled, const ShaderCompiledFunction &compiled,
const std::filesystem::path &includePath) { const std::filesystem::path &includePath) {
ShadyErrorCodes codes = driver_load_source_file( ShadyErrorCodes codes = driver_load_source_file(
SrcSlim, SrcSlim,
shaderSource.length(), shaderSource.length(),
shaderSource.c_str(), shaderSource.c_str(),
module module
); );
switch (codes) { switch (codes) {
...@@ -46,7 +46,7 @@ namespace vkcv::shader { ...@@ -46,7 +46,7 @@ namespace vkcv::shader {
DriverConfig config = default_driver_config(); DriverConfig config = default_driver_config();
config.target = TgtSPV; config.target = TgtSPV;
config.output_filename = tmp_path.string().c_str(); config.output_filename = tmp_path.string().c_str();
codes = driver_compile(&config, module); codes = driver_compile(&config, module);
...@@ -78,10 +78,10 @@ namespace vkcv::shader { ...@@ -78,10 +78,10 @@ namespace vkcv::shader {
} }
static bool shadyCompileArena(IrArena* arena, static bool shadyCompileArena(IrArena* arena,
ShaderStage shaderStage, ShaderStage shaderStage,
const std::string& shaderSource, const std::string& shaderSource,
const ShaderCompiledFunction &compiled, const ShaderCompiledFunction &compiled,
const std::filesystem::path &includePath) { const std::filesystem::path &includePath) {
Module* module = new_module(arena, "slim_module"); Module* module = new_module(arena, "slim_module");
if (nullptr == module) { if (nullptr == module) {
...@@ -92,11 +92,11 @@ namespace vkcv::shader { ...@@ -92,11 +92,11 @@ namespace vkcv::shader {
return shadyCompileModule(module, shaderStage, shaderSource, compiled, includePath); return shadyCompileModule(module, shaderStage, shaderSource, compiled, includePath);
} }
bool SlimCompiler::compileSource(ShaderStage shaderStage, bool SlimCompiler::compileSource(ShaderStage shaderStage,
const std::string& shaderSource, const std::string& shaderSource,
const ShaderCompiledFunction& compiled, const ShaderCompiledFunction& compiled,
const std::filesystem::path& includePath) { const std::filesystem::path& includePath) {
if (ShaderStage::COMPUTE != shaderStage) { if (ShaderStage::COMPUTE != shaderStage) {
vkcv_log(LogLevel::ERROR, "Shader stage not supported"); vkcv_log(LogLevel::ERROR, "Shader stage not supported");
return false; return false;
} }
...@@ -112,7 +112,7 @@ namespace vkcv::shader { ...@@ -112,7 +112,7 @@ namespace vkcv::shader {
bool result = shadyCompileArena(arena, shaderStage, shaderSource, compiled, includePath); bool result = shadyCompileArena(arena, shaderStage, shaderSource, compiled, includePath);
destroy_ir_arena(arena); destroy_ir_arena(arena);
return result; return result;
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment