summaryrefslogtreecommitdiffstats
path: root/Graphics
diff options
context:
space:
mode:
authorazhirnov <zh1dron@gmail.com>2020-09-02 22:59:01 +0000
committerazhirnov <zh1dron@gmail.com>2020-09-02 22:59:01 +0000
commitab01643f73deb37e828d46a007e8643e449b28f9 (patch)
treed333d91ed570f8ce297b82e6b18e35eb48715b6d /Graphics
parentfixed compilation on UWP, use FXC by default on D3D12 (diff)
downloadDiligentCore-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.txt7
-rw-r--r--Graphics/GLSLTools/include/SPIRVUtils.hpp2
-rw-r--r--Graphics/GLSLTools/src/SPIRVUtils.cpp171
-rw-r--r--Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp19
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,