From 749d440dbf43181e8106c482ee621e60bc3605f7 Mon Sep 17 00:00:00 2001 From: Egor Yusov Date: Tue, 30 Oct 2018 20:02:11 -0700 Subject: Stripping reflection information from SPIRV binaries before creating Vulkan shader modules to fix validation error --- Graphics/GraphicsEngineVulkan/CMakeLists.txt | 1 + .../src/PipelineStateVkImpl.cpp | 36 ++++++++++++++++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) (limited to 'Graphics/GraphicsEngineVulkan') diff --git a/Graphics/GraphicsEngineVulkan/CMakeLists.txt b/Graphics/GraphicsEngineVulkan/CMakeLists.txt index e7ab3e44..e96ba9a5 100644 --- a/Graphics/GraphicsEngineVulkan/CMakeLists.txt +++ b/Graphics/GraphicsEngineVulkan/CMakeLists.txt @@ -176,6 +176,7 @@ set(PRIVATE_DEPENDENCIES TargetPlatform GraphicsEngineNextGenBase GLSLTools + SPIRV-Tools-opt ) if(PLATFORM_WIN32) diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp index a5cd7342..cc80fa02 100644 --- a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp @@ -31,6 +31,7 @@ #include "ShaderResourceBindingVkImpl.h" #include "EngineMemory.h" #include "StringTools.h" +#include "spirv-tools/optimizer.hpp" namespace Diligent { @@ -126,6 +127,22 @@ VkRenderPassCreateInfo PipelineStateVkImpl::GetRenderPassCreateInfo( return RenderPassCI; } +static std::vector StripReflection(const std::vector& OriginalSPIRV) +{ + std::vector 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; +} + PipelineStateVkImpl :: PipelineStateVkImpl(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pDeviceVk, const PipelineStateDesc& PipelineDesc) : @@ -195,8 +212,23 @@ PipelineStateVkImpl :: PipelineStateVkImpl(IReferenceCounters* pRefCounters ShaderModuleCI.pNext = nullptr; ShaderModuleCI.flags = 0; const auto& SPIRV = ShaderSPIRVs[s]; - ShaderModuleCI.codeSize = SPIRV.size() * sizeof(uint32_t); - ShaderModuleCI.pCode = SPIRV.data(); + + // We have to strip reflection instructions to fix the follownig validation error: + // SPIR-V module not valid: DecorateStringGOOGLE requires one of the following extensions: SPV_GOOGLE_decorate_string + // Optimizer also performs validation and may catch problems with the byte code. + auto StrippedSPIRV = StripReflection(SPIRV); + if (!StrippedSPIRV.empty()) + { + ShaderModuleCI.codeSize = StrippedSPIRV.size() * sizeof(uint32_t); + ShaderModuleCI.pCode = StrippedSPIRV.data(); + } + else + { + LOG_ERROR("Failed to strip reflection information from shader '", pShaderVk->GetDesc().Name, "'. This may indicate a problem with the byte code."); + ShaderModuleCI.codeSize = SPIRV.size() * sizeof(uint32_t); + ShaderModuleCI.pCode = SPIRV.data(); + } + m_ShaderModules[s] = LogicalDevice.CreateShaderModule(ShaderModuleCI, m_Desc.Name); StageCI.module = m_ShaderModules[s]; -- cgit v1.2.3