From fabdc39ba722e716f09cfeccf969204f1a0b1b78 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 21 Mar 2023 20:23:10 +0100 Subject: [PATCH] Update ZVulkan --- .../ZVulkan/include/zvulkan/vulkanbuilders.h | 33 ++++- libraries/ZVulkan/src/vulkanbuilders.cpp | 134 ++++++++++++++++-- 2 files changed, 155 insertions(+), 12 deletions(-) diff --git a/libraries/ZVulkan/include/zvulkan/vulkanbuilders.h b/libraries/ZVulkan/include/zvulkan/vulkanbuilders.h index 2a8d6c425..104d9ceef 100644 --- a/libraries/ZVulkan/include/zvulkan/vulkanbuilders.h +++ b/libraries/ZVulkan/include/zvulkan/vulkanbuilders.h @@ -196,6 +196,26 @@ private: VkDeviceSize minAlignment = 0; }; +enum class ShaderType +{ + Vertex, + TessControl, + TessEvaluation, + Geometry, + Fragment, + Compute +}; + +class ShaderIncludeResult +{ +public: + ShaderIncludeResult(std::string name, std::string text) : name(std::move(name)), text(std::move(text)) { } + ShaderIncludeResult(std::string error) : text(std::move(error)) { } + + std::string name; // fully resolved name of the included header file + std::string text; // the file contents - or include error message if name is empty +}; + class ShaderBuilder { public: @@ -204,16 +224,23 @@ public: static void Init(); static void Deinit(); - ShaderBuilder& VertexShader(const std::string &code); - ShaderBuilder& FragmentShader(const std::string&code); + ShaderBuilder& Type(ShaderType type); + ShaderBuilder& AddSource(const std::string& name, const std::string& code); + + ShaderBuilder& OnIncludeSystem(std::function onIncludeSystem); + ShaderBuilder& OnIncludeLocal(std::function onIncludeLocal); + ShaderBuilder& DebugName(const char* name) { debugName = name; return *this; } std::unique_ptr Create(const char *shadername, VulkanDevice *device); private: - std::string code; + std::vector> sources; + std::function onIncludeSystem; + std::function onIncludeLocal; int stage = 0; const char* debugName = nullptr; + friend class ShaderBuilderIncluderImpl; }; class AccelerationStructureBuilder diff --git a/libraries/ZVulkan/src/vulkanbuilders.cpp b/libraries/ZVulkan/src/vulkanbuilders.cpp index 36ae7fff4..5a0db352a 100644 --- a/libraries/ZVulkan/src/vulkanbuilders.cpp +++ b/libraries/ZVulkan/src/vulkanbuilders.cpp @@ -128,29 +128,143 @@ ShaderBuilder::ShaderBuilder() { } -ShaderBuilder& ShaderBuilder::VertexShader(const std::string& c) +ShaderBuilder& ShaderBuilder::Type(ShaderType type) { - code = c; - stage = EShLanguage::EShLangVertex; + switch (type) + { + case ShaderType::Vertex: stage = EShLanguage::EShLangVertex; break; + case ShaderType::TessControl: stage = EShLanguage::EShLangTessControl; break; + case ShaderType::TessEvaluation: stage = EShLanguage::EShLangTessEvaluation; break; + case ShaderType::Geometry: stage = EShLanguage::EShLangGeometry; break; + case ShaderType::Fragment: stage = EShLanguage::EShLangFragment; break; + case ShaderType::Compute: stage = EShLanguage::EShLangCompute; break; + } return *this; } -ShaderBuilder& ShaderBuilder::FragmentShader(const std::string& c) +ShaderBuilder& ShaderBuilder::AddSource(const std::string& name, const std::string& code) { - code = c; - stage = EShLanguage::EShLangFragment; + sources.push_back({ name, code }); return *this; } +ShaderBuilder& ShaderBuilder::OnIncludeSystem(std::function onIncludeSystem) +{ + this->onIncludeSystem = std::move(onIncludeSystem); + return *this; +} + +ShaderBuilder& ShaderBuilder::OnIncludeLocal(std::function onIncludeLocal) +{ + this->onIncludeLocal = std::move(onIncludeLocal); + return *this; +} + +class ShaderBuilderIncluderImpl : public glslang::TShader::Includer +{ +public: + ShaderBuilderIncluderImpl(ShaderBuilder* shaderBuilder) : shaderBuilder(shaderBuilder) + { + } + + IncludeResult* includeSystem(const char* headerName, const char* includerName, size_t inclusionDepth) override + { + if (!shaderBuilder->onIncludeSystem) + { + return nullptr; + } + + try + { + std::unique_ptr result; + try + { + result = std::make_unique(shaderBuilder->onIncludeSystem(headerName, includerName, inclusionDepth)); + } + catch (const std::exception& e) + { + result = std::make_unique(e.what()); + } + + if (!result || (result->name.empty() && result->text.empty())) + { + return nullptr; + } + + IncludeResult* outer = new IncludeResult(result->name, result->text.data(), result->text.size(), result.get()); + result.release(); + return outer; + } + catch (...) + { + return nullptr; + } + } + + IncludeResult* includeLocal(const char* headerName, const char* includerName, size_t inclusionDepth) override + { + if (!shaderBuilder->onIncludeLocal) + { + return nullptr; + } + + try + { + std::unique_ptr result; + try + { + result = std::make_unique(shaderBuilder->onIncludeLocal(headerName, includerName, inclusionDepth)); + } + catch (const std::exception& e) + { + result = std::make_unique(e.what()); + } + + if (!result || (result->name.empty() && result->text.empty())) + { + return nullptr; + } + + IncludeResult* outer = new IncludeResult(result->name, result->text.data(), result->text.size(), result.get()); + result.release(); + return outer; + } + catch (...) + { + return nullptr; + } + } + + void releaseInclude(IncludeResult* result) override + { + if (result) + { + delete (ShaderIncludeResult*)result->userData; + delete result; + } + } + +private: + ShaderBuilder* shaderBuilder = nullptr; +}; + std::unique_ptr ShaderBuilder::Create(const char *shadername, VulkanDevice *device) { EShLanguage stage = (EShLanguage)this->stage; - const char *sources[] = { code.c_str() }; + + std::vector namesC, sourcesC; + std::vector lengthsC; + for (const auto& s : sources) + { + namesC.push_back(s.first.c_str()); + sourcesC.push_back(s.second.c_str()); + lengthsC.push_back((int)s.second.size()); + } TBuiltInResource resources = DefaultTBuiltInResource; glslang::TShader shader(stage); - shader.setStrings(sources, 1); + shader.setStringsWithLengthsAndNames(sourcesC.data(), lengthsC.data(), namesC.data(), (int)sources.size()); shader.setEnvInput(glslang::EShSourceGlsl, stage, glslang::EShClientVulkan, 100); if (device->Instance->ApiVersion >= VK_API_VERSION_1_2) { @@ -162,7 +276,9 @@ std::unique_ptr ShaderBuilder::Create(const char *shadername, Vulk shader.setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_0); shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_0); } - bool compileSuccess = shader.parse(&resources, 110, false, EShMsgVulkanRules); + + ShaderBuilderIncluderImpl includer(this); + bool compileSuccess = shader.parse(&resources, 110, false, EShMsgVulkanRules, includer); if (!compileSuccess) { throw std::runtime_error(std::string("Shader compile failed: ") + shader.getInfoLog());