2020-08-15 20:09:16 -04:00
|
|
|
#include "shadercompiler.hpp"
|
|
|
|
|
|
|
|
#include <spirv_msl.hpp>
|
|
|
|
#include <SPIRV/GlslangToSpv.h>
|
|
|
|
|
|
|
|
#include "log.hpp"
|
|
|
|
#include "string_utils.hpp"
|
|
|
|
#include "includer.hpp"
|
|
|
|
#include "defaultresources.hpp"
|
|
|
|
|
2021-02-16 17:10:37 -05:00
|
|
|
static inline std::vector<std::string> include_path;
|
2020-08-15 20:09:16 -04:00
|
|
|
|
|
|
|
ShaderCompiler::ShaderCompiler() {
|
|
|
|
glslang::InitializeProcess();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShaderCompiler::set_include_path(const std::string_view path) {
|
2021-05-09 19:10:23 -04:00
|
|
|
include_path.emplace_back(path.data());
|
2020-08-15 20:09:16 -04:00
|
|
|
}
|
|
|
|
|
2021-05-09 19:10:23 -04:00
|
|
|
std::vector<uint32_t> compile_glsl_to_spv(const std::string_view source_string, const EShLanguage shader_language, const CompileOptions& options) {
|
2020-09-23 09:53:45 -04:00
|
|
|
std::string newString = "#version 460 core\n";
|
2020-08-15 20:09:16 -04:00
|
|
|
|
|
|
|
newString += "#extension GL_GOOGLE_include_directive : enable\n";
|
|
|
|
newString += "#extension GL_GOOGLE_cpp_style_line_directive : enable\n";
|
|
|
|
|
|
|
|
for(auto& definition : options.definitions)
|
|
|
|
newString += "#define " + definition + "\n";
|
|
|
|
|
|
|
|
newString += "#line 1\n";
|
|
|
|
|
|
|
|
newString += source_string;
|
2022-02-20 22:28:35 -05:00
|
|
|
|
|
|
|
if(options.enable_wgpu_compat) {
|
|
|
|
// in some wacky world the webgpu devs live in, push constants do not exist.
|
|
|
|
|
|
|
|
// alright, so to make webgpu happy we are going to hand-waive all of our push constant blocks
|
|
|
|
// away into UBOs. let's start by rewriting our GLSL. yay...
|
|
|
|
newString = replace_substring(newString, "push_constant", "binding = 10");
|
|
|
|
}
|
|
|
|
|
2020-08-15 20:09:16 -04:00
|
|
|
const char* InputCString = newString.c_str();
|
|
|
|
|
2021-05-09 19:10:23 -04:00
|
|
|
glslang::TShader shader(shader_language);
|
|
|
|
shader.setStrings(&InputCString, 1);
|
2022-02-20 22:28:35 -05:00
|
|
|
|
2020-08-15 20:09:16 -04:00
|
|
|
int ClientInputSemanticsVersion = 100; // maps to, say, #define VULKAN 100
|
|
|
|
|
2021-05-09 19:10:23 -04:00
|
|
|
shader.setEnvInput(glslang::EShSourceGlsl,
|
|
|
|
shader_language,
|
|
|
|
glslang::EShClientVulkan,
|
|
|
|
ClientInputSemanticsVersion);
|
|
|
|
|
|
|
|
// we are targeting vulkan 1.1, so that uses SPIR-V 1.3
|
|
|
|
shader.setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_1);
|
|
|
|
shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_3);
|
|
|
|
|
|
|
|
DirStackFileIncluder file_includer;
|
|
|
|
for(const auto& path : include_path)
|
|
|
|
file_includer.pushExternalLocalDirectory(path);
|
|
|
|
if (!shader.parse(&DefaultTBuiltInResource, 100, false, EShMsgDefault, file_includer)) {
|
2021-09-13 23:41:54 -04:00
|
|
|
prism::log("{}", shader.getInfoLog());
|
2020-08-15 20:09:16 -04:00
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
glslang::TProgram Program;
|
2021-05-09 19:10:23 -04:00
|
|
|
Program.addShader(&shader);
|
2020-08-15 20:09:16 -04:00
|
|
|
|
2021-05-09 19:10:23 -04:00
|
|
|
if(!Program.link(EShMsgDefault)) {
|
2021-09-13 23:41:54 -04:00
|
|
|
prism::log("Failed to link shader: {} {} {}", source_string.data(), shader.getInfoLog(), shader.getInfoDebugLog());
|
2020-08-15 20:09:16 -04:00
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
2020-09-23 09:53:45 -04:00
|
|
|
|
2020-08-15 20:09:16 -04:00
|
|
|
std::vector<unsigned int> SpirV;
|
|
|
|
spv::SpvBuildLogger logger;
|
2022-02-18 14:38:08 -05:00
|
|
|
|
2020-08-15 20:09:16 -04:00
|
|
|
glslang::SpvOptions spvOptions;
|
2022-02-18 14:38:08 -05:00
|
|
|
spvOptions.generateDebugInfo = true;
|
|
|
|
|
2020-08-15 20:09:16 -04:00
|
|
|
glslang::GlslangToSpv(*Program.getIntermediate(shader_language), SpirV, &logger, &spvOptions);
|
|
|
|
|
|
|
|
return SpirV;
|
|
|
|
}
|
|
|
|
|
2022-02-20 22:28:35 -05:00
|
|
|
std::optional<ShaderSource> ShaderCompiler::compile(const ShaderLanguage from_language, const ShaderStage shader_stage, const ShaderSource& shader_source, const ShaderLanguage to_language, CompileOptions options) {
|
2020-08-15 20:09:16 -04:00
|
|
|
if(from_language != ShaderLanguage::GLSL) {
|
2021-09-13 23:41:54 -04:00
|
|
|
prism::log("Non-supported input language!");
|
2020-08-15 20:09:16 -04:00
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
EShLanguage lang = EShLangMiss;
|
|
|
|
switch(shader_stage) {
|
|
|
|
case ShaderStage::Vertex:
|
|
|
|
lang = EShLangVertex;
|
|
|
|
break;
|
|
|
|
case ShaderStage::Fragment:
|
|
|
|
lang = EShLangFragment;
|
|
|
|
break;
|
2020-09-22 15:39:20 -04:00
|
|
|
case ShaderStage::Compute:
|
|
|
|
lang = EShLangCompute;
|
|
|
|
break;
|
2020-08-15 20:09:16 -04:00
|
|
|
}
|
|
|
|
|
2022-02-20 22:28:35 -05:00
|
|
|
options.enable_wgpu_compat = to_language == ShaderLanguage::WGSL;
|
|
|
|
|
2020-08-15 20:09:16 -04:00
|
|
|
auto spirv = compile_glsl_to_spv(shader_source.as_string(), lang, options);
|
|
|
|
if(spirv.empty()) {
|
2021-09-13 23:41:54 -04:00
|
|
|
prism::log("SPIRV generation failed!");
|
2020-08-15 20:09:16 -04:00
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
2020-08-15 20:35:46 -04:00
|
|
|
switch(to_language) {
|
2022-02-20 22:28:35 -05:00
|
|
|
case ShaderLanguage::WGSL:
|
2020-08-15 20:35:46 -04:00
|
|
|
case ShaderLanguage::SPIRV:
|
2021-05-09 19:10:23 -04:00
|
|
|
return ShaderSource(spirv);
|
2022-02-15 12:32:42 -05:00
|
|
|
case ShaderLanguage::MSL: {
|
|
|
|
spirv_cross::CompilerMSL msl(std::move(spirv));
|
|
|
|
|
|
|
|
spirv_cross::CompilerMSL::Options opts;
|
|
|
|
if(options.is_apple_mobile) {
|
|
|
|
opts.platform = spirv_cross::CompilerMSL::Options::Platform::iOS;
|
|
|
|
} else {
|
|
|
|
opts.platform = spirv_cross::CompilerMSL::Options::Platform::macOS;
|
|
|
|
}
|
|
|
|
opts.enable_decoration_binding = true;
|
|
|
|
|
|
|
|
msl.set_msl_options(opts);
|
|
|
|
|
|
|
|
return ShaderSource(msl.compile());
|
|
|
|
}
|
2022-02-15 09:21:56 -05:00
|
|
|
case ShaderLanguage::HLSL:
|
|
|
|
prism::log("Unimplemented shader language: HLSL");
|
|
|
|
return ShaderSource(spirv);
|
2020-08-15 20:35:46 -04:00
|
|
|
default:
|
|
|
|
return {};
|
2020-08-15 20:09:16 -04:00
|
|
|
}
|
|
|
|
}
|