diff options
| author | Jay Kwak <82421531+jkwak-work@users.noreply.github.com> | 2024-07-17 17:00:05 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-07-17 17:00:05 -0700 |
| commit | 32b1e25e359f8daf5254301dca8be308e8e1e2ab (patch) | |
| tree | 2dd2bf7324b771c4a0aa989194a9b1d3b219af18 | |
| parent | 2db15080085856ed9b5f20642dbb354aac59a888 (diff) | |
Use slang-glslang.dll for spirv-validation (#4642)
* Use slang-glslang.dll for spirv-validation
This change replaces the use of "spirv-val.exe" with an API call to
"spvtools::SpirvTools::Validate()".
Closes #4610
| -rw-r--r-- | source/compiler-core/slang-downstream-compiler.h | 3 | ||||
| -rw-r--r-- | source/compiler-core/slang-glslang-compiler.cpp | 17 | ||||
| -rw-r--r-- | source/slang-glslang/slang-glslang.cpp | 20 | ||||
| -rw-r--r-- | source/slang-glslang/slang-glslang.h | 1 | ||||
| -rw-r--r-- | source/slang-llvm/slang-llvm.cpp | 3 | ||||
| -rw-r--r-- | source/slang/slang-emit-spirv.cpp | 17 | ||||
| -rw-r--r-- | source/slang/slang-emit.cpp | 16 | ||||
| -rw-r--r-- | source/slang/slang-spirv-val.cpp | 41 | ||||
| -rw-r--r-- | source/slang/slang-spirv-val.h | 1 |
9 files changed, 59 insertions, 60 deletions
diff --git a/source/compiler-core/slang-downstream-compiler.h b/source/compiler-core/slang-downstream-compiler.h index 14e924f8b..95793eaa3 100644 --- a/source/compiler-core/slang-downstream-compiler.h +++ b/source/compiler-core/slang-downstream-compiler.h @@ -309,6 +309,8 @@ public: virtual SLANG_NO_THROW SlangResult SLANG_MCALL convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) = 0; /// Get the version of this compiler virtual SLANG_NO_THROW SlangResult SLANG_MCALL getVersionString(slang::IBlob** outVersionString) = 0; + /// Validate and return the result + virtual SLANG_NO_THROW SlangResult SLANG_MCALL validate(const uint32_t* contents, int contentsSize) = 0; /// True if underlying compiler uses file system to communicate source virtual SLANG_NO_THROW bool SLANG_MCALL isFileBased() = 0; @@ -327,6 +329,7 @@ public: virtual SLANG_NO_THROW bool SLANG_MCALL canConvert(const ArtifactDesc& from, const ArtifactDesc& to) SLANG_OVERRIDE { SLANG_UNUSED(from); SLANG_UNUSED(to); return false; } virtual SLANG_NO_THROW SlangResult SLANG_MCALL convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) SLANG_OVERRIDE; virtual SLANG_NO_THROW SlangResult SLANG_MCALL getVersionString(slang::IBlob** outVersionString) SLANG_OVERRIDE { *outVersionString = nullptr; return SLANG_FAIL; } + virtual SLANG_NO_THROW SlangResult SLANG_MCALL validate(const uint32_t* contents, int contentsSize) SLANG_OVERRIDE { SLANG_UNUSED(contents); SLANG_UNUSED(contentsSize); return SLANG_FAIL; } DownstreamCompilerBase(const Desc& desc): m_desc(desc) diff --git a/source/compiler-core/slang-glslang-compiler.cpp b/source/compiler-core/slang-glslang-compiler.cpp index e0a537757..9ef8e7fb4 100644 --- a/source/compiler-core/slang-glslang-compiler.cpp +++ b/source/compiler-core/slang-glslang-compiler.cpp @@ -48,6 +48,7 @@ public: virtual SLANG_NO_THROW SlangResult SLANG_MCALL convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) SLANG_OVERRIDE; virtual SLANG_NO_THROW bool SLANG_MCALL isFileBased() SLANG_OVERRIDE { return false; } virtual SLANG_NO_THROW SlangResult SLANG_MCALL getVersionString(slang::IBlob** outVersionString) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL validate(const uint32_t* contents, int contentsSize) SLANG_OVERRIDE; /// Must be called before use SlangResult init(ISlangSharedLibrary* library); @@ -61,6 +62,7 @@ protected: glslang_CompileFunc_1_0 m_compile_1_0 = nullptr; glslang_CompileFunc_1_1 m_compile_1_1 = nullptr; glslang_CompileFunc_1_2 m_compile_1_2 = nullptr; + glslang_ValidateSPIRVFunc m_validate = nullptr; ComPtr<ISlangSharedLibrary> m_sharedLibrary; @@ -72,6 +74,7 @@ SlangResult GlslangDownstreamCompiler::init(ISlangSharedLibrary* library) m_compile_1_0 = (glslang_CompileFunc_1_0)library->findFuncByName("glslang_compile"); m_compile_1_1 = (glslang_CompileFunc_1_1)library->findFuncByName("glslang_compile_1_1"); m_compile_1_2 = (glslang_CompileFunc_1_2)library->findFuncByName("glslang_compile_1_2"); + m_validate = (glslang_ValidateSPIRVFunc)library->findFuncByName("glslang_validateSPIRV"); if (m_compile_1_0 == nullptr && m_compile_1_1 == nullptr && m_compile_1_2 == nullptr) @@ -281,6 +284,20 @@ SlangResult GlslangDownstreamCompiler::compile(const CompileOptions& inOptions, return SLANG_OK; } +SlangResult GlslangDownstreamCompiler::validate(const uint32_t* contents, int contentsSize) +{ + if (m_validate == nullptr) + { + return SLANG_FAIL; + } + + if (m_validate(contents, contentsSize)) + { + return SLANG_OK; + } + return SLANG_FAIL; +} + bool GlslangDownstreamCompiler::canConvert(const ArtifactDesc& from, const ArtifactDesc& to) { // Can only disassemble blobs that are SPIR-V diff --git a/source/slang-glslang/slang-glslang.cpp b/source/slang-glslang/slang-glslang.cpp index cdbc95031..8ae85b631 100644 --- a/source/slang-glslang/slang-glslang.cpp +++ b/source/slang-glslang/slang-glslang.cpp @@ -145,6 +145,26 @@ struct SPIRVOptimizationDiagnostic std::string message; }; +// Validate the given SPIRV-ASM instructions. +extern "C" +#ifdef _MSC_VER +_declspec(dllexport) +#else +__attribute__((__visibility__("default"))) +#endif +bool glslang_validateSPIRV(const uint32_t* contents, int contentsSize) +{ + spv_target_env target_env = SPV_ENV_VULKAN_1_3; + + spvtools::ValidatorOptions options; + options.SetScalarBlockLayout(true); + + spvtools::SpirvTools tools(target_env); + //tools.SetMessageConsumer(spvtools::utils::CLIMessageConsumer); + + return tools.Validate(contents, contentsSize, options); +} + // Apply the SPIRV-Tools optimizer to generated SPIR-V based on the desired optimization level // TODO: add flag for optimizing SPIR-V size as well static void glslang_optimizeSPIRV(spv_target_env targetEnv, const glslang_CompileRequest_1_2& request, std::vector<SPIRVOptimizationDiagnostic>& outDiags, std::vector<unsigned int>& ioSpirv) diff --git a/source/slang-glslang/slang-glslang.h b/source/slang-glslang/slang-glslang.h index 68c24d889..00205a114 100644 --- a/source/slang-glslang/slang-glslang.h +++ b/source/slang-glslang/slang-glslang.h @@ -147,5 +147,6 @@ inline void glslang_CompileRequest_1_2::set(const glslang_CompileRequest_1_1& in typedef int (*glslang_CompileFunc_1_0)(glslang_CompileRequest_1_0* request); typedef int (*glslang_CompileFunc_1_1)(glslang_CompileRequest_1_1* request); typedef int (*glslang_CompileFunc_1_2)(glslang_CompileRequest_1_2* request); +typedef bool (*glslang_ValidateSPIRVFunc)(const uint32_t* contents, int contentsSize); #endif diff --git a/source/slang-llvm/slang-llvm.cpp b/source/slang-llvm/slang-llvm.cpp index 0c14fbeb6..b84a79340 100644 --- a/source/slang-llvm/slang-llvm.cpp +++ b/source/slang-llvm/slang-llvm.cpp @@ -121,7 +121,7 @@ using namespace llvm::orc; using namespace Slang; -class LLVMDownstreamCompiler : public IDownstreamCompiler, ComBaseObject +class LLVMDownstreamCompiler : public ComBaseObject, public IDownstreamCompiler { public: typedef ComBaseObject Super; @@ -139,6 +139,7 @@ public: virtual SLANG_NO_THROW SlangResult SLANG_MCALL convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) SLANG_OVERRIDE; virtual SLANG_NO_THROW bool SLANG_MCALL isFileBased() SLANG_OVERRIDE { return false; } virtual SLANG_NO_THROW SlangResult SLANG_MCALL getVersionString(slang::IBlob** outVersionString) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL validate(const uint32_t* contents, int contentsSize) SLANG_OVERRIDE { SLANG_UNUSED(contents); SLANG_UNUSED(contentsSize); return SLANG_FAIL; } LLVMDownstreamCompiler(): m_desc(SLANG_PASS_THROUGH_LLVM, SemanticVersion(LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR, LLVM_VERSION_PATCH)) diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp index 1040017da..6b84668e3 100644 --- a/source/slang/slang-emit-spirv.cpp +++ b/source/slang/slang-emit-spirv.cpp @@ -6576,23 +6576,6 @@ SlangResult emitSPIRVFromIR( (uint8_t const*) context.m_words.getBuffer(), context.m_words.getCount() * Index(sizeof(context.m_words[0]))); - StringBuilder runSpirvValEnvVar; - PlatformUtil::getEnvironmentVariable(UnownedStringSlice("SLANG_RUN_SPIRV_VALIDATION"), runSpirvValEnvVar); - if (runSpirvValEnvVar.getUnownedSlice() == "1" - && !codeGenContext->shouldSkipSPIRVValidation()) - { - const auto validationResult = debugValidateSPIRV(spirvOut); - // If validation isn't available, don't say it failed, it's just a debug - // feature so we can skip - if (SLANG_FAILED(validationResult) && validationResult != SLANG_E_NOT_AVAILABLE) - { - codeGenContext->getSink()->diagnoseWithoutSourceView( - SourceLoc{}, - Diagnostics::spirvValidationFailed - ); - return validationResult; - } - } return SLANG_OK; } diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp index cb8460173..679d8ce88 100644 --- a/source/slang/slang-emit.cpp +++ b/source/slang/slang-emit.cpp @@ -1704,6 +1704,22 @@ SlangResult emitSPIRVForEntryPointsDirectly( PassThroughMode::SpirvOpt, codeGenContext->getSink()); if (compiler) { + if (!codeGenContext->shouldSkipSPIRVValidation()) + { + StringBuilder runSpirvValEnvVar; + PlatformUtil::getEnvironmentVariable(UnownedStringSlice("SLANG_RUN_SPIRV_VALIDATION"), runSpirvValEnvVar); + if (runSpirvValEnvVar.getUnownedSlice() == "1") + { + if (SLANG_FAILED(compiler->validate((uint32_t*)spirv.getBuffer(), int(spirv.getCount()/4)))) + { + codeGenContext->getSink()->diagnoseWithoutSourceView( + SourceLoc{}, + Diagnostics::spirvValidationFailed + ); + } + } + } + ComPtr<IArtifact> optimizedArtifact; DownstreamCompileOptions downstreamOptions; downstreamOptions.sourceArtifacts = makeSlice(artifact.readRef(), 1); diff --git a/source/slang/slang-spirv-val.cpp b/source/slang/slang-spirv-val.cpp index faacb9c59..585ff5c94 100644 --- a/source/slang/slang-spirv-val.cpp +++ b/source/slang/slang-spirv-val.cpp @@ -38,46 +38,5 @@ SlangResult disassembleSPIRV(const List<uint8_t>& spirv, String& outErr, String& return ret == 0 ? SLANG_OK : SLANG_FAIL; } -SlangResult debugValidateSPIRV(const List<uint8_t>& spirv) -{ - // Set up our process - CommandLine commandLine; - commandLine.m_executableLocation.setName("spirv-val"); - commandLine.addArg("--target-env"); - commandLine.addArg("vulkan1.3"); - commandLine.addArg("--scalar-block-layout"); - RefPtr<Process> p; - const auto createResult = Process::create(commandLine, 0, p); - // If we failed to even start the process, then validation isn't available - if(SLANG_FAILED(createResult)) - return SLANG_E_NOT_AVAILABLE; - const auto in = p->getStream(StdStreamType::In); - const auto out = p->getStream(StdStreamType::Out); - const auto err = p->getStream(StdStreamType::ErrorOut); - - List<Byte> outData; - List<Byte> errData; - SLANG_RETURN_ON_FAIL(StreamUtil::readAndWrite(in, spirv.getArrayView(), out, outData, err, errData)); - - // Wait for it to finish - if(!p->waitForTermination(1000)) - return SLANG_FAIL; - - // If we failed, dump the spirv first. - const auto ret = p->getReturnValue(); - if(ret != 0) - { - String spirvDisErr; - String spirvDis; - disassembleSPIRV(spirv, spirvDisErr, spirvDis); - fwrite(spirvDisErr.getBuffer(), spirvDisErr.getLength(), 1, stderr); - fwrite(spirvDis.getBuffer(), spirvDis.getLength(), 1, stderr); - } - - fwrite(outData.getBuffer(), outData.getCount(), 1, stderr); - fwrite(errData.getBuffer(), errData.getCount(), 1, stderr); - - return ret == 0 ? SLANG_OK : SLANG_FAIL; -} } diff --git a/source/slang/slang-spirv-val.h b/source/slang/slang-spirv-val.h index 7ee55693a..bb0730849 100644 --- a/source/slang/slang-spirv-val.h +++ b/source/slang/slang-spirv-val.h @@ -5,7 +5,6 @@ namespace Slang { -SlangResult debugValidateSPIRV(const List<uint8_t>& spirv); SlangResult disassembleSPIRV(const List<uint8_t>& spirv, String& outErr, String& outDis); } |
