diff options
| author | azhirnov <zh1dron@gmail.com> | 2020-09-02 22:59:01 +0000 |
|---|---|---|
| committer | azhirnov <zh1dron@gmail.com> | 2020-09-02 22:59:01 +0000 |
| commit | ab01643f73deb37e828d46a007e8643e449b28f9 (patch) | |
| tree | d333d91ed570f8ce297b82e6b18e35eb48715b6d /Graphics | |
| parent | fixed compilation on UWP, use FXC by default on D3D12 (diff) | |
| download | DiligentCore-ab01643f73deb37e828d46a007e8643e449b28f9.tar.gz DiligentCore-ab01643f73deb37e828d46a007e8643e449b28f9.zip | |
fixed validation errors for SPIRV that compiled with DXC
Diffstat (limited to 'Graphics')
| -rw-r--r-- | Graphics/GLSLTools/CMakeLists.txt | 7 | ||||
| -rw-r--r-- | Graphics/GLSLTools/include/SPIRVUtils.hpp | 2 | ||||
| -rw-r--r-- | Graphics/GLSLTools/src/SPIRVUtils.cpp | 171 | ||||
| -rw-r--r-- | Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp | 19 |
4 files changed, 183 insertions, 16 deletions
diff --git a/Graphics/GLSLTools/CMakeLists.txt b/Graphics/GLSLTools/CMakeLists.txt index d9bc011a..442c0d97 100644 --- a/Graphics/GLSLTools/CMakeLists.txt +++ b/Graphics/GLSLTools/CMakeLists.txt @@ -80,6 +80,13 @@ if(VULKAN_SUPPORTED) endif() endif() +if(NOT ${DILIGENT_NO_GLSLANG}) + target_include_directories(Diligent-GLSLTools + PRIVATE + ${spirv-tools_BINARY_DIR} + ../../ThirdParty/SPIRV-Tools) +endif() + set_common_target_properties(Diligent-GLSLTools) source_group("src" FILES ${SOURCE}) diff --git a/Graphics/GLSLTools/include/SPIRVUtils.hpp b/Graphics/GLSLTools/include/SPIRVUtils.hpp index 50025303..8c645a64 100644 --- a/Graphics/GLSLTools/include/SPIRVUtils.hpp +++ b/Graphics/GLSLTools/include/SPIRVUtils.hpp @@ -46,4 +46,6 @@ std::vector<unsigned int> HLSLtoSPIRV(const ShaderCreateInfo& Attribs, const char* ExtraDefinitions, IDataBlob** ppCompilerOutput); +std::vector<uint32_t> StripReflection(const std::vector<uint32_t>& OriginalSPIRV); + } // namespace Diligent
\ No newline at end of file diff --git a/Graphics/GLSLTools/src/SPIRVUtils.cpp b/Graphics/GLSLTools/src/SPIRVUtils.cpp index 5ae9d3a1..fe4ec326 100644 --- a/Graphics/GLSLTools/src/SPIRVUtils.cpp +++ b/Graphics/GLSLTools/src/SPIRVUtils.cpp @@ -44,6 +44,18 @@ #include "spirv-tools/optimizer.hpp" +// SPIRV-Tools source +#ifdef _MSC_VER +# pragma warning(push, 0) +#endif +#include "source/opt/ir_context.h" +#include "source/opt/module.h" +#include "source/opt/pass.h" +#include "source/opt/instruction.h" +#ifdef _MSC_VER +# pragma warning(pop) +#endif + // clang-format off static const char g_HLSLDefinitions[] = { @@ -553,5 +565,164 @@ std::vector<unsigned int> GLSLtoSPIRV(const SHADER_TYPE ShaderType, const char* return std::move(SPIRV); } } +} // namespace Diligent + +// this is modified version of StripReflectInfoPass from SPIRV-Tools +class StripReflectInfoPass2 : public spvtools::opt::Pass +{ +public: + const char* name() const override { return "strip-reflect-2"; } + + // Return the mask of preserved Analyses. + spvtools::opt::IRContext::Analysis GetPreservedAnalyses() override + { + using namespace spvtools::opt; + return IRContext::kAnalysisInstrToBlockMapping | + IRContext::kAnalysisCombinators | IRContext::kAnalysisCFG | + IRContext::kAnalysisDominatorAnalysis | + IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap | + IRContext::kAnalysisConstants | IRContext::kAnalysisTypes; + } + + Status Process() override + { + using namespace spvtools::opt; + bool modified = false; + + std::vector<Instruction*> to_remove; + + for (auto& inst : context()->module()->annotations()) + { + switch (inst.opcode()) + { + case SpvOpDecorateStringGOOGLE: + to_remove.push_back(&inst); + break; + + case SpvOpMemberDecorateStringGOOGLE: + to_remove.push_back(&inst); + break; + + case SpvOpDecorateId: + if (inst.GetSingleWordInOperand(1) == + SpvDecorationHlslCounterBufferGOOGLE) + { + to_remove.push_back(&inst); + } + break; + + default: + break; + } + } + + for (auto& inst : context()->module()->extensions()) + { + const char* ext_name = + reinterpret_cast<const char*>(&inst.GetInOperand(0).words[0]); + if (0 == std::strcmp(ext_name, "SPV_GOOGLE_hlsl_functionality1")) + { + to_remove.push_back(&inst); + } + else if (0 == std::strcmp(ext_name, "SPV_GOOGLE_decorate_string")) + { + to_remove.push_back(&inst); + } + else if (0 == std::strcmp(ext_name, "SPV_GOOGLE_user_type")) + { + to_remove.push_back(&inst); + } + else if (0 == std::strcmp(ext_name, "SPV_KHR_non_semantic_info")) + { + to_remove.push_back(&inst); + } + } + + // clear all debug data now if it hasn't been cleared already, to remove any + // remaining OpString that may have been referenced by non-semantic extinsts + for (auto& dbg : context()->debugs1()) to_remove.push_back(&dbg); + for (auto& dbg : context()->debugs2()) to_remove.push_back(&dbg); + for (auto& dbg : context()->debugs3()) to_remove.push_back(&dbg); + for (auto& dbg : context()->ext_inst_debuginfo()) to_remove.push_back(&dbg); + + // remove any extended inst imports that are non semantic + std::unordered_set<uint32_t> non_semantic_sets; + for (auto& inst : context()->module()->ext_inst_imports()) + { + assert(inst.opcode() == SpvOpExtInstImport && + "Expecting an import of an extension's instruction set."); + const char* extension_name = + reinterpret_cast<const char*>(&inst.GetInOperand(0).words[0]); + if (0 == std::strncmp(extension_name, "NonSemantic.", 12)) + { + non_semantic_sets.insert(inst.result_id()); + to_remove.push_back(&inst); + } + } + + // if we removed some non-semantic sets, then iterate over the instructions in + // the module to remove any OpExtInst that referenced those sets + if (!non_semantic_sets.empty()) + { + context()->module()->ForEachInst( + [&non_semantic_sets, &to_remove](Instruction* inst) { + if (inst->opcode() == SpvOpExtInst) + { + if (non_semantic_sets.find(inst->GetSingleWordInOperand(0)) != + non_semantic_sets.end()) + { + to_remove.push_back(inst); + } + } + }); + } + + // OpName must come first, since they may refer to other debug instructions. + // If they are after the instructions that refer to, then they will be killed + // when that instruction is killed, which will lead to a double kill. + std::sort(to_remove.begin(), to_remove.end(), + [](Instruction* lhs, Instruction* rhs) -> bool { + if (lhs->opcode() == SpvOpName && rhs->opcode() != SpvOpName) + return true; + return false; + }); + + for (auto* inst : to_remove) + { + modified = true; + context()->KillInst(inst); + } + + return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; + } +}; + +struct spvtools::Optimizer::PassToken::Impl +{ + Impl(std::unique_ptr<opt::Pass> p) : + pass(std::move(p)) {} + + std::unique_ptr<opt::Pass> pass; // Internal implementation pass. +}; + +namespace Diligent +{ + +std::vector<uint32_t> StripReflection(const std::vector<uint32_t>& OriginalSPIRV) +{ + std::vector<uint32_t> StrippedSPIRV; + spvtools::Optimizer SpirvOptimizer(SPV_ENV_VULKAN_1_0); + // Decorations defined in SPV_GOOGLE_hlsl_functionality1 are the only instructions + // removed by strip-reflect-info pass. SPIRV offsets become INVALID after this operation. + SpirvOptimizer.RegisterPass(spvtools::MakeUnique<spvtools::Optimizer::PassToken::Impl>(spvtools::MakeUnique<StripReflectInfoPass2>())); + //SpirvOptimizer.RegisterPass(spvtools::CreateStripReflectInfoPass()); + auto res = SpirvOptimizer.Run(OriginalSPIRV.data(), OriginalSPIRV.size(), &StrippedSPIRV); + if (!res) + { + // Optimized SPIRV may be invalid + StrippedSPIRV.clear(); + } + return StrippedSPIRV; +} } // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp index 65150c48..6ca51b1e 100644 --- a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp @@ -39,7 +39,7 @@ #if !DILIGENT_NO_HLSL -# include "spirv-tools/optimizer.hpp" +# include "SPIRVUtils.hpp" #endif namespace Diligent @@ -129,25 +129,12 @@ RenderPassDesc PipelineStateVkImpl::GetImplicitRenderPassDesc( return RPDesc; } +#if DILIGENT_NO_HLSL static std::vector<uint32_t> StripReflection(const std::vector<uint32_t>& OriginalSPIRV) { -#if DILIGENT_NO_HLSL return OriginalSPIRV; -#else - std::vector<uint32_t> StrippedSPIRV; - spvtools::Optimizer SpirvOptimizer(SPV_ENV_VULKAN_1_0); - // Decorations defined in SPV_GOOGLE_hlsl_functionality1 are the only instructions - // removed by strip-reflect-info pass. SPIRV offsets become INVALID after this operation. - SpirvOptimizer.RegisterPass(spvtools::CreateStripReflectInfoPass()); - auto res = SpirvOptimizer.Run(OriginalSPIRV.data(), OriginalSPIRV.size(), &StrippedSPIRV); - if (!res) - { - // Optimized SPIRV may be invalid - StrippedSPIRV.clear(); - } - return StrippedSPIRV; -#endif } +#endif PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pDeviceVk, |
