From 15581a674f54a98cae19783926b903555fd01738 Mon Sep 17 00:00:00 2001 From: acheney <acheney@nvidia.com> Date: Fri, 28 Feb 2025 15:15:01 -0500 Subject: [PATCH 1/5] Support SPIR-V deferred linking option The new option "SkipDownstreamLinking" will defer final downstream IR linking to the user application. This option only has an effect if there are modules that were precompiled to the target IR using precompileForTarget(). Until now, the default behavior for SPIR-V was to use deferred linking, and the default behavior for DXIL was to use immediate/internal linking in Slang. This change only affects the SPIR-V behavior such that both deferred and non-deferred linking is supported based on the new option. To support the non-deferred option, Slang will internally call into SPIRV-Tools-link to reconstitute a complete SPIR-V shader program when necessary (due to modules having been precompiled to target IR). Otherwise, if SkipDownstreamLinking is enabled, the shader returned by e.g. getTargetCode() or getEntryPointCode() may have import linkage to the SPIR-V embedded in the constituent modules. Closes #4994 --- include/slang-gfx.h | 9 +++ include/slang.h | 3 + .../compiler-core/slang-downstream-compiler.h | 10 +++ .../compiler-core/slang-glslang-compiler.cpp | 37 +++++++++++ source/compiler-core/slang-glslang-compiler.h | 8 +++ source/slang-glslang/slang-glslang.cpp | 2 +- source/slang/slang-compiler.cpp | 6 ++ source/slang/slang-compiler.h | 7 +++ source/slang/slang-emit.cpp | 61 ++++++++++++++++++- tools/gfx-unit-test/gfx-test-util.cpp | 9 ++- tools/gfx-unit-test/gfx-test-util.h | 10 ++- tools/gfx-unit-test/precompiled-module-2.cpp | 55 +++++++++++++---- tools/gfx/renderer-shared.cpp | 10 +-- tools/gfx/vulkan/vk-device.h | 3 + tools/gfx/vulkan/vk-shader-program.cpp | 16 ++++- 15 files changed, 223 insertions(+), 23 deletions(-) diff --git a/include/slang-gfx.h b/include/slang-gfx.h index 6f46fed339..db9dcbacba 100644 --- a/include/slang-gfx.h +++ b/include/slang-gfx.h @@ -163,6 +163,12 @@ class IShaderProgram : public ISlangUnknown SeparateEntryPointCompilation }; + enum class DownstreamLinkMode + { + None, + Deferred, + }; + struct Desc { // TODO: Tess doesn't like this but doesn't know what to do about it @@ -180,6 +186,9 @@ class IShaderProgram : public ISlangUnknown // An array of Slang entry points. The size of the array must be `entryPointCount`. // Each element must define only 1 Slang EntryPoint. slang::IComponentType** slangEntryPoints = nullptr; + + // Indicates whether the app is responsible for final downstream linking. + DownstreamLinkMode downstreamLinkMode = DownstreamLinkMode::None; }; struct CreateDesc2 diff --git a/include/slang.h b/include/slang.h index 66fd317c64..9c7fcd560c 100644 --- a/include/slang.h +++ b/include/slang.h @@ -653,6 +653,7 @@ typedef uint32_t SlangSizeT; SLANG_PASS_THROUGH_SPIRV_OPT, ///< SPIRV-opt SLANG_PASS_THROUGH_METAL, ///< Metal compiler SLANG_PASS_THROUGH_TINT, ///< Tint WGSL compiler + SLANG_PASS_THROUGH_SPIRV_LINK, ///< SPIRV-link SLANG_PASS_THROUGH_COUNT_OF, }; @@ -1008,6 +1009,8 @@ typedef uint32_t SlangSizeT; EmitReflectionJSON, // bool SaveGLSLModuleBinSource, + + SkipDownstreamLinking, // bool, experimental CountOf, }; diff --git a/source/compiler-core/slang-downstream-compiler.h b/source/compiler-core/slang-downstream-compiler.h index 82aaef1076..6dfe6ebf84 100644 --- a/source/compiler-core/slang-downstream-compiler.h +++ b/source/compiler-core/slang-downstream-compiler.h @@ -343,6 +343,16 @@ class IDownstreamCompiler : public ICastable /// True if underlying compiler uses file system to communicate source virtual SLANG_NO_THROW bool SLANG_MCALL isFileBased() = 0; + + virtual SLANG_NO_THROW int SLANG_MCALL + link(const uint32_t** modules, const uint32_t* moduleSizes, + const uint32_t moduleCount, + IArtifact** outArtifact) { + SLANG_UNREFERENCED_PARAMETER(modules); + SLANG_UNREFERENCED_PARAMETER(moduleSizes); + SLANG_UNREFERENCED_PARAMETER(moduleCount); + SLANG_UNREFERENCED_PARAMETER(outArtifact); + return 0;} }; class DownstreamCompilerBase : public ComBaseObject, public IDownstreamCompiler diff --git a/source/compiler-core/slang-glslang-compiler.cpp b/source/compiler-core/slang-glslang-compiler.cpp index b619f468f3..92233e2849 100644 --- a/source/compiler-core/slang-glslang-compiler.cpp +++ b/source/compiler-core/slang-glslang-compiler.cpp @@ -49,6 +49,9 @@ class GlslangDownstreamCompiler : public DownstreamCompilerBase validate(const uint32_t* contents, int contentsSize) SLANG_OVERRIDE; virtual SLANG_NO_THROW SlangResult SLANG_MCALL disassemble(const uint32_t* contents, int contentsSize) SLANG_OVERRIDE; + int link(const uint32_t** modules, const uint32_t* moduleSizes, + const uint32_t moduleCount, + IArtifact** outArtifact) SLANG_OVERRIDE; /// Must be called before use SlangResult init(ISlangSharedLibrary* library); @@ -66,6 +69,7 @@ class GlslangDownstreamCompiler : public DownstreamCompilerBase glslang_CompileFunc_1_2 m_compile_1_2 = nullptr; glslang_ValidateSPIRVFunc m_validate = nullptr; glslang_DisassembleSPIRVFunc m_disassemble = nullptr; + glslang_LinkSPIRVFunc m_link = nullptr; ComPtr<ISlangSharedLibrary> m_sharedLibrary; @@ -80,6 +84,7 @@ SlangResult GlslangDownstreamCompiler::init(ISlangSharedLibrary* library) m_validate = (glslang_ValidateSPIRVFunc)library->findFuncByName("glslang_validateSPIRV"); m_disassemble = (glslang_DisassembleSPIRVFunc)library->findFuncByName("glslang_disassembleSPIRV"); + m_link = (glslang_LinkSPIRVFunc)library->findFuncByName("glslang_linkSPIRV"); if (m_compile_1_0 == nullptr && m_compile_1_1 == nullptr && m_compile_1_2 == nullptr) { @@ -323,6 +328,30 @@ SlangResult GlslangDownstreamCompiler::disassemble(const uint32_t* contents, int return SLANG_FAIL; } +SlangResult GlslangDownstreamCompiler::link(const uint32_t** modules, const uint32_t* moduleSizes, + const uint32_t moduleCount, + IArtifact** outArtifact) +{ + glslang_LinkRequest request; + memset(&request, 0, sizeof(request)); + + request.modules = modules; + request.moduleSizes = moduleSizes; + request.moduleCount = moduleCount; + + if (!m_link(&request)) + { + return SLANG_FAIL; + } + + auto artifact = ArtifactUtil::createArtifactForCompileTarget(SLANG_SPIRV); + artifact->addRepresentationUnknown( + Slang::RawBlob::create(request.linkResult, request.linkResultSize * sizeof(uint32_t))); + + *outArtifact = artifact.detach(); + return SLANG_OK; +} + bool GlslangDownstreamCompiler::canConvert(const ArtifactDesc& from, const ArtifactDesc& to) { // Can only disassemble blobs that are SPIR-V @@ -467,6 +496,14 @@ SlangResult SpirvDisDownstreamCompilerUtil::locateCompilers( return locateGlslangSpirvDownstreamCompiler(path, loader, set, SLANG_PASS_THROUGH_SPIRV_DIS); } +SlangResult SpirvLinkDownstreamCompilerUtil::locateCompilers( + const String& path, + ISlangSharedLibraryLoader* loader, + DownstreamCompilerSet* set) +{ + return locateGlslangSpirvDownstreamCompiler(path, loader, set, SLANG_PASS_THROUGH_SPIRV_LINK); +} + #else // SLANG_ENABLE_GLSLANG_SUPPORT /* static */ SlangResult GlslangDownstreamCompilerUtil::locateCompilers( diff --git a/source/compiler-core/slang-glslang-compiler.h b/source/compiler-core/slang-glslang-compiler.h index 73cc611357..d56ad7114e 100644 --- a/source/compiler-core/slang-glslang-compiler.h +++ b/source/compiler-core/slang-glslang-compiler.h @@ -32,6 +32,14 @@ struct SpirvDisDownstreamCompilerUtil DownstreamCompilerSet* set); }; +struct SpirvLinkDownstreamCompilerUtil +{ + static SlangResult locateCompilers( + const String& path, + ISlangSharedLibraryLoader* loader, + DownstreamCompilerSet* set); +}; + } // namespace Slang #endif diff --git a/source/slang-glslang/slang-glslang.cpp b/source/slang-glslang/slang-glslang.cpp index bbb3f6afc4..b3370d803d 100644 --- a/source/slang-glslang/slang-glslang.cpp +++ b/source/slang-glslang/slang-glslang.cpp @@ -1037,7 +1037,7 @@ extern "C" request->linkResultSize = linkedBinary.size(); } - return success; + return success == SPV_SUCCESS; } catch (...) { diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp index 04ebb753c1..a7172ae7ae 100644 --- a/source/slang/slang-compiler.cpp +++ b/source/slang/slang-compiler.cpp @@ -2647,6 +2647,12 @@ bool CodeGenContext::shouldDumpIR() return getTargetProgram()->getOptionSet().getBoolOption(CompilerOptionName::DumpIr); } +bool CodeGenContext::shouldSkipDownstreamLinking() +{ + return getTargetProgram()->getOptionSet().getBoolOption( + CompilerOptionName::SkipDownstreamLinking); +} + bool CodeGenContext::shouldReportCheckpointIntermediates() { return getTargetProgram()->getOptionSet().getBoolOption( diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h index 6175d25ccd..f1ed834a60 100644 --- a/source/slang/slang-compiler.h +++ b/source/slang/slang-compiler.h @@ -1385,6 +1385,7 @@ enum class PassThroughMode : SlangPassThroughIntegral SpirvOpt = SLANG_PASS_THROUGH_SPIRV_OPT, ///< pass thorugh spirv to spirv-opt MetalC = SLANG_PASS_THROUGH_METAL, Tint = SLANG_PASS_THROUGH_TINT, ///< pass through spirv to Tint API + SpirvLink = SLANG_PASS_THROUGH_SPIRV_LINK, ///< pass through spirv to spirv-link CountOf = SLANG_PASS_THROUGH_COUNT_OF, }; void printDiagnosticArg(StringBuilder& sb, PassThroughMode val); @@ -2886,6 +2887,12 @@ struct CodeGenContext // removed between IR linking and target source generation. bool removeAvailableInDownstreamIR = false; + // Determines if program level compilation like getTargetCode() or getEntryPointCode() + // should return a fully linked downstream program or just the glue SPIR-V/DXIL that + // imports and uses the precompiled SPIR-V/DXIL from constituent modules. + // This is a no-op if modules are not precompiled. + bool shouldSkipDownstreamLinking(); + protected: CodeGenTarget m_targetFormat = CodeGenTarget::Unknown; ExtensionTracker* m_extensionTracker = nullptr; diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp index 847c5b55c0..e7c50e6381 100644 --- a/source/slang/slang-emit.cpp +++ b/source/slang/slang-emit.cpp @@ -2093,10 +2093,69 @@ SlangResult emitSPIRVForEntryPointsDirectly( if (compiler) { #if 0 - // Dump the unoptimized SPIRV after lowering from slang IR -> SPIRV + // Dump the unoptimized/unlinked SPIRV after lowering from slang IR -> SPIRV compiler->disassemble((uint32_t*)spirv.getBuffer(), int(spirv.getCount() / 4)); #endif + bool isPrecompilation = codeGenContext->getTargetProgram()->getOptionSet().getBoolOption( + CompilerOptionName::EmbedDownstreamIR); + + if (!isPrecompilation && !codeGenContext->shouldSkipDownstreamLinking()) + { + ComPtr<IArtifact> linkedArtifact; + + // collect spirv files + std::vector<uint32_t*> spirvFiles; + std::vector<uint32_t> spirvSizes; + + // Start with the SPIR-V we just generated. + // SPIRV-Tools-link expects the size in 32-bit words + // whereas the spirv blob size is in bytes. + spirvFiles.push_back((uint32_t*)spirv.getBuffer()); + spirvSizes.push_back(int(spirv.getCount()) / 4); + + // Iterate over all modules in the linkedIR. For each module, if it + // contains an embedded downstream ir instruction, add it to the list + // of spirv files. + auto program = codeGenContext->getProgram(); + + program->enumerateIRModules( + [&](IRModule* irModule) + { + for (auto globalInst : irModule->getModuleInst()->getChildren()) + { + if (auto inst = as<IREmbeddedDownstreamIR>(globalInst)) + { + if (inst->getTarget() == CodeGenTarget::SPIRV) + { + auto slice = inst->getBlob()->getStringSlice(); + spirvFiles.push_back((uint32_t*)slice.begin()); + spirvSizes.push_back(int(slice.getLength()) / 4); + } + } + } + } + ); + + SLANG_ASSERT(int(spirv.getCount()) % 4 == 0); + SLANG_ASSERT(spirvFiles.size() == spirvSizes.size()); + SlangResult linkresult = compiler->link( + (const uint32_t**)spirvFiles.data(), + spirvSizes.data(), + spirvFiles.size(), + linkedArtifact.writeRef()); + + if (linkresult != SLANG_OK) + { + return SLANG_FAIL; + } + + ComPtr<ISlangBlob> blob; + linkedArtifact->loadBlob(ArtifactKeep::No, blob.writeRef()); + + artifact = _Move(linkedArtifact); + } + if (!codeGenContext->shouldSkipSPIRVValidation()) { StringBuilder runSpirvValEnvVar; diff --git a/tools/gfx-unit-test/gfx-test-util.cpp b/tools/gfx-unit-test/gfx-test-util.cpp index 2bbe654160..c649a13173 100644 --- a/tools/gfx-unit-test/gfx-test-util.cpp +++ b/tools/gfx-unit-test/gfx-test-util.cpp @@ -80,7 +80,8 @@ Slang::Result loadComputeProgram( Slang::ComPtr<gfx::IShaderProgram>& outShaderProgram, const char* shaderModuleName, const char* entryPointName, - slang::ProgramLayout*& slangReflection) + slang::ProgramLayout*& slangReflection, + PrecompilationMode precompilationMode) { Slang::ComPtr<slang::IBlob> diagnosticsBlob; slang::IModule* module = slangSession->loadModule(shaderModuleName, diagnosticsBlob.writeRef()); @@ -115,6 +116,12 @@ Slang::Result loadComputeProgram( gfx::IShaderProgram::Desc programDesc = {}; programDesc.slangGlobalScope = composedProgram.get(); + if (precompilationMode == PrecompilationMode::ExternalLink) + { + programDesc.downstreamLinkMode = gfx::IShaderProgram::DownstreamLinkMode::Deferred; + } else { + programDesc.downstreamLinkMode = gfx::IShaderProgram::DownstreamLinkMode::None; + } auto shaderProgram = device->createProgram(programDesc); diff --git a/tools/gfx-unit-test/gfx-test-util.h b/tools/gfx-unit-test/gfx-test-util.h index 5586701621..94a2d97706 100644 --- a/tools/gfx-unit-test/gfx-test-util.h +++ b/tools/gfx-unit-test/gfx-test-util.h @@ -7,6 +7,13 @@ namespace gfx_test { + enum class PrecompilationMode + { + None, + SlangIR, + InternalLink, + ExternalLink, + }; /// Helper function for print out diagnostic messages output by Slang compiler. void diagnoseIfNeeded(slang::IBlob* diagnosticsBlob); @@ -24,7 +31,8 @@ Slang::Result loadComputeProgram( Slang::ComPtr<gfx::IShaderProgram>& outShaderProgram, const char* shaderModuleName, const char* entryPointName, - slang::ProgramLayout*& slangReflection); + slang::ProgramLayout*& slangReflection, + PrecompilationMode precompilationMode = PrecompilationMode::None); Slang::Result loadComputeProgramFromSource( gfx::IDevice* device, diff --git a/tools/gfx-unit-test/precompiled-module-2.cpp b/tools/gfx-unit-test/precompiled-module-2.cpp index ca9f8b565a..8bbe8d2828 100644 --- a/tools/gfx-unit-test/precompiled-module-2.cpp +++ b/tools/gfx-unit-test/precompiled-module-2.cpp @@ -17,7 +17,7 @@ static Slang::Result precompileProgram( gfx::IDevice* device, ISlangMutableFileSystem* fileSys, const char* shaderModuleName, - bool precompileToTarget) + PrecompilationMode precompilationMode) { Slang::ComPtr<slang::ISession> slangSession; SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef())); @@ -37,7 +37,8 @@ static Slang::Result precompileProgram( if (!module) return SLANG_FAIL; - if (precompileToTarget) + if (precompilationMode == PrecompilationMode::InternalLink || + precompilationMode == PrecompilationMode::ExternalLink) { SlangCompileTarget target; switch (device->getDeviceInfo().deviceType) @@ -82,7 +83,7 @@ static Slang::Result precompileProgram( void precompiledModule2TestImplCommon( IDevice* device, UnitTestContext* context, - bool precompileToTarget) + PrecompilationMode precompilationMode) { Slang::ComPtr<ITransientResourceHeap> transientHeap; ITransientResourceHeap::Desc transientHeapDesc = {}; @@ -100,7 +101,7 @@ void precompiledModule2TestImplCommon( device, memoryFileSystem.get(), "precompiled-module-imported", - precompileToTarget)); + precompilationMode)); // Next, load the precompiled slang program. Slang::ComPtr<slang::ISession> slangSession; @@ -121,6 +122,17 @@ void precompiledModule2TestImplCommon( } sessionDesc.targets = &targetDesc; sessionDesc.fileSystem = memoryFileSystem.get(); + + std::vector<slang::CompilerOptionEntry> options; + slang::CompilerOptionEntry skipDownstreamLinkingOption; + skipDownstreamLinkingOption.name = slang::CompilerOptionName::SkipDownstreamLinking; + skipDownstreamLinkingOption.value.kind = slang::CompilerOptionValueKind::Int; + skipDownstreamLinkingOption.value.intValue0 = + precompilationMode == PrecompilationMode::ExternalLink; + options.push_back(skipDownstreamLinkingOption); + + sessionDesc.compilerOptionEntries = options.data(); + sessionDesc.compilerOptionEntryCount = options.size(); auto globalSession = slangSession->getGlobalSession(); globalSession->createSession(sessionDesc, slangSession.writeRef()); @@ -147,7 +159,8 @@ void precompiledModule2TestImplCommon( shaderProgram, "precompiled-module", "computeMain", - slangReflection)); + slangReflection, + precompilationMode)); ComputePipelineStateDesc pipelineDesc = {}; pipelineDesc.program = shaderProgram.get(); @@ -208,12 +221,17 @@ void precompiledModule2TestImplCommon( void precompiledModule2TestImpl(IDevice* device, UnitTestContext* context) { - precompiledModule2TestImplCommon(device, context, false); + precompiledModule2TestImplCommon(device, context, PrecompilationMode::SlangIR); +} + +void precompiledTargetModule2InternalLinkTestImpl(IDevice* device, UnitTestContext* context) +{ + precompiledModule2TestImplCommon(device, context, PrecompilationMode::InternalLink); } -void precompiledTargetModule2TestImpl(IDevice* device, UnitTestContext* context) +void precompiledTargetModule2ExternalLinkTestImpl(IDevice* device, UnitTestContext* context) { - precompiledModule2TestImplCommon(device, context, true); + precompiledModule2TestImplCommon(device, context, PrecompilationMode::ExternalLink); } SLANG_UNIT_TEST(precompiledModule2D3D12) @@ -221,19 +239,32 @@ SLANG_UNIT_TEST(precompiledModule2D3D12) runTestImpl(precompiledModule2TestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); } -SLANG_UNIT_TEST(precompiledTargetModule2D3D12) +SLANG_UNIT_TEST(precompiledTargetModuleInternalLink2D3D12) { - runTestImpl(precompiledTargetModule2TestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); + runTestImpl(precompiledTargetModule2InternalLinkTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); } +/* +// Unavailable on D3D12/DXIL currently +SLANG_UNIT_TEST(precompiledTargetModuleExternalLink2D3D12) +{ + runTestImpl(precompiledTargetModule2ExternalLinkTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); +} +*/ + SLANG_UNIT_TEST(precompiledModule2Vulkan) { runTestImpl(precompiledModule2TestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); } -SLANG_UNIT_TEST(precompiledTargetModule2Vulkan) +SLANG_UNIT_TEST(precompiledTargetModule2InternalLinkVulkan) +{ + runTestImpl(precompiledTargetModule2InternalLinkTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); +} + +SLANG_UNIT_TEST(precompiledTargetModule2ExternalLinkVulkan) { - runTestImpl(precompiledTargetModule2TestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); + runTestImpl(precompiledTargetModule2ExternalLinkTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); } } // namespace gfx_test diff --git a/tools/gfx/renderer-shared.cpp b/tools/gfx/renderer-shared.cpp index ae4ea3eefa..edd271ecb2 100644 --- a/tools/gfx/renderer-shared.cpp +++ b/tools/gfx/renderer-shared.cpp @@ -1133,11 +1133,13 @@ Result ShaderProgramBase::compileShaders(RendererBase* device) kernelCodes.add(downstreamIR); } - // If target precompilation was used, kernelCode may only represent the - // glue code holding together the bits of precompiled target IR. - // Collect those dependency target IRs too. + // If target precompilation with deferred downstream linking is enabled, + // kernelCode may only represent the glue code holding together the + // bits of precompiled target IR. It's the application's job to pull it + // together. Collect those dependency target IRs too. ComPtr<slang::IModulePrecompileService_Experimental> componentPrecompileService; - if (entryPointComponent->queryInterface( + if (this->desc.downstreamLinkMode == DownstreamLinkMode::Deferred && + entryPointComponent->queryInterface( slang::IModulePrecompileService_Experimental::getTypeGuid(), (void**)componentPrecompileService.writeRef()) == SLANG_OK) { diff --git a/tools/gfx/vulkan/vk-device.h b/tools/gfx/vulkan/vk-device.h index 27cc4c3ce8..06e19ad7e1 100644 --- a/tools/gfx/vulkan/vk-device.h +++ b/tools/gfx/vulkan/vk-device.h @@ -223,6 +223,9 @@ class DeviceImpl : public RendererBase VkSampler m_defaultSampler; RefPtr<FramebufferImpl> m_emptyFramebuffer; + + // If true, slang will skip downstream linking, so we need to do it ourselves + bool m_skipsDownstreamLinking = false; }; } // namespace vk diff --git a/tools/gfx/vulkan/vk-shader-program.cpp b/tools/gfx/vulkan/vk-shader-program.cpp index 1627c95a7a..719be93d87 100644 --- a/tools/gfx/vulkan/vk-shader-program.cpp +++ b/tools/gfx/vulkan/vk-shader-program.cpp @@ -74,10 +74,20 @@ Result ShaderProgramImpl::createShaderModule( slang::EntryPointReflection* entryPointInfo, List<ComPtr<ISlangBlob>>& kernelCodes) { - ComPtr<ISlangBlob> linkedKernel = m_device->m_glslang.linkSPIRV(kernelCodes); - if (!linkedKernel) + ComPtr<ISlangBlob> linkedKernel; + ComPtr<slang::ISession> slangSession; + m_device->getSlangSession(slangSession.writeRef()); + if (kernelCodes.getCount() == 1) { - return SLANG_FAIL; + linkedKernel = kernelCodes[0]; + } + else + { + linkedKernel = m_device->m_glslang.linkSPIRV(kernelCodes); + if (!linkedKernel) + { + return SLANG_FAIL; + } } m_codeBlobs.add(linkedKernel); From 7199102defa0f671a99d7fb3db9a43e6ba13d3d5 Mon Sep 17 00:00:00 2001 From: acheney <acheney@nvidia.com> Date: Fri, 28 Feb 2025 15:37:24 -0500 Subject: [PATCH 2/5] Fix werror --- source/slang/slang-emit.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp index e7c50e6381..36fd12740a 100644 --- a/source/slang/slang-emit.cpp +++ b/source/slang/slang-emit.cpp @@ -2141,8 +2141,8 @@ SlangResult emitSPIRVForEntryPointsDirectly( SLANG_ASSERT(spirvFiles.size() == spirvSizes.size()); SlangResult linkresult = compiler->link( (const uint32_t**)spirvFiles.data(), - spirvSizes.data(), - spirvFiles.size(), + (const uint32_t*)spirvSizes.data(), + (uint32_t)spirvFiles.size(), linkedArtifact.writeRef()); if (linkresult != SLANG_OK) From 1f9543ae01d6413a490f862f817fe3e516e214ed Mon Sep 17 00:00:00 2001 From: acheney <acheney@nvidia.com> Date: Fri, 28 Feb 2025 23:03:54 -0500 Subject: [PATCH 3/5] Fix bug --- source/slang/slang-emit.cpp | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp index 36fd12740a..ebaae3c2e8 100644 --- a/source/slang/slang-emit.cpp +++ b/source/slang/slang-emit.cpp @@ -2139,21 +2139,24 @@ SlangResult emitSPIRVForEntryPointsDirectly( SLANG_ASSERT(int(spirv.getCount()) % 4 == 0); SLANG_ASSERT(spirvFiles.size() == spirvSizes.size()); - SlangResult linkresult = compiler->link( - (const uint32_t**)spirvFiles.data(), - (const uint32_t*)spirvSizes.data(), - (uint32_t)spirvFiles.size(), - linkedArtifact.writeRef()); - - if (linkresult != SLANG_OK) + + if (spirvFiles.size() > 1) { - return SLANG_FAIL; - } + SlangResult linkresult = compiler->link( + (const uint32_t**)spirvFiles.data(), + (const uint32_t*)spirvSizes.data(), + (uint32_t)spirvFiles.size(), + linkedArtifact.writeRef()); - ComPtr<ISlangBlob> blob; - linkedArtifact->loadBlob(ArtifactKeep::No, blob.writeRef()); - - artifact = _Move(linkedArtifact); + if (linkresult != SLANG_OK) + { + return SLANG_FAIL; + } + + ComPtr<ISlangBlob> blob; + linkedArtifact->loadBlob(ArtifactKeep::No, blob.writeRef()); + artifact = _Move(linkedArtifact); + } } if (!codeGenContext->shouldSkipSPIRVValidation()) From d49b82feca179f16e8604db3e435a0f8057d25db Mon Sep 17 00:00:00 2001 From: acheney <acheney@nvidia.com> Date: Sat, 1 Mar 2025 12:06:24 -0500 Subject: [PATCH 4/5] Use list not vector --- source/slang/slang-emit.cpp | 22 ++++++++++---------- tools/gfx-unit-test/precompiled-module-2.cpp | 8 +++---- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp index ebaae3c2e8..83ceb8f859 100644 --- a/source/slang/slang-emit.cpp +++ b/source/slang/slang-emit.cpp @@ -2105,14 +2105,14 @@ SlangResult emitSPIRVForEntryPointsDirectly( ComPtr<IArtifact> linkedArtifact; // collect spirv files - std::vector<uint32_t*> spirvFiles; - std::vector<uint32_t> spirvSizes; + List<uint32_t*> spirvFiles; + List<uint32_t> spirvSizes; // Start with the SPIR-V we just generated. // SPIRV-Tools-link expects the size in 32-bit words // whereas the spirv blob size is in bytes. - spirvFiles.push_back((uint32_t*)spirv.getBuffer()); - spirvSizes.push_back(int(spirv.getCount()) / 4); + spirvFiles.add((uint32_t*)spirv.getBuffer()); + spirvSizes.add(int(spirv.getCount()) / 4); // Iterate over all modules in the linkedIR. For each module, if it // contains an embedded downstream ir instruction, add it to the list @@ -2129,8 +2129,8 @@ SlangResult emitSPIRVForEntryPointsDirectly( if (inst->getTarget() == CodeGenTarget::SPIRV) { auto slice = inst->getBlob()->getStringSlice(); - spirvFiles.push_back((uint32_t*)slice.begin()); - spirvSizes.push_back(int(slice.getLength()) / 4); + spirvFiles.add((uint32_t*)slice.begin()); + spirvSizes.add(int(slice.getLength()) / 4); } } } @@ -2138,14 +2138,14 @@ SlangResult emitSPIRVForEntryPointsDirectly( ); SLANG_ASSERT(int(spirv.getCount()) % 4 == 0); - SLANG_ASSERT(spirvFiles.size() == spirvSizes.size()); + SLANG_ASSERT(spirvFiles.getCount() == spirvSizes.getCount()); - if (spirvFiles.size() > 1) + if (spirvFiles.getCount() > 1) { SlangResult linkresult = compiler->link( - (const uint32_t**)spirvFiles.data(), - (const uint32_t*)spirvSizes.data(), - (uint32_t)spirvFiles.size(), + (const uint32_t**)spirvFiles.getBuffer(), + (const uint32_t*)spirvSizes.getBuffer(), + (uint32_t)spirvFiles.getCount(), linkedArtifact.writeRef()); if (linkresult != SLANG_OK) diff --git a/tools/gfx-unit-test/precompiled-module-2.cpp b/tools/gfx-unit-test/precompiled-module-2.cpp index 8bbe8d2828..c62317a07a 100644 --- a/tools/gfx-unit-test/precompiled-module-2.cpp +++ b/tools/gfx-unit-test/precompiled-module-2.cpp @@ -123,16 +123,16 @@ void precompiledModule2TestImplCommon( sessionDesc.targets = &targetDesc; sessionDesc.fileSystem = memoryFileSystem.get(); - std::vector<slang::CompilerOptionEntry> options; + Slang::List<slang::CompilerOptionEntry> options; slang::CompilerOptionEntry skipDownstreamLinkingOption; skipDownstreamLinkingOption.name = slang::CompilerOptionName::SkipDownstreamLinking; skipDownstreamLinkingOption.value.kind = slang::CompilerOptionValueKind::Int; skipDownstreamLinkingOption.value.intValue0 = precompilationMode == PrecompilationMode::ExternalLink; - options.push_back(skipDownstreamLinkingOption); + options.add(skipDownstreamLinkingOption); - sessionDesc.compilerOptionEntries = options.data(); - sessionDesc.compilerOptionEntryCount = options.size(); + sessionDesc.compilerOptionEntries = options.getBuffer(); + sessionDesc.compilerOptionEntryCount = options.getCount(); auto globalSession = slangSession->getGlobalSession(); globalSession->createSession(sessionDesc, slangSession.writeRef()); From 4d8b0151f3c974b733c2c0b0e975e9da0f45d443 Mon Sep 17 00:00:00 2001 From: slangbot <186143334+slangbot@users.noreply.github.com> Date: Sat, 1 Mar 2025 17:07:34 +0000 Subject: [PATCH 5/5] format code --- include/slang.h | 2 +- .../compiler-core/slang-downstream-compiler.h | 21 +++++++++++-------- .../compiler-core/slang-glslang-compiler.cpp | 16 ++++++++------ source/slang/slang-compiler.h | 4 ++-- source/slang/slang-emit.cpp | 3 +-- tools/gfx-unit-test/gfx-test-util.cpp | 4 +++- tools/gfx-unit-test/gfx-test-util.h | 14 ++++++------- tools/gfx-unit-test/precompiled-module-2.cpp | 18 ++++++++++++---- tools/gfx/vulkan/vk-shader-program.cpp | 2 +- 9 files changed, 51 insertions(+), 33 deletions(-) diff --git a/include/slang.h b/include/slang.h index 9c7fcd560c..d000dab9f5 100644 --- a/include/slang.h +++ b/include/slang.h @@ -1010,7 +1010,7 @@ typedef uint32_t SlangSizeT; EmitReflectionJSON, // bool SaveGLSLModuleBinSource, - SkipDownstreamLinking, // bool, experimental + SkipDownstreamLinking, // bool, experimental CountOf, }; diff --git a/source/compiler-core/slang-downstream-compiler.h b/source/compiler-core/slang-downstream-compiler.h index 6dfe6ebf84..c96003cc4f 100644 --- a/source/compiler-core/slang-downstream-compiler.h +++ b/source/compiler-core/slang-downstream-compiler.h @@ -344,15 +344,18 @@ class IDownstreamCompiler : public ICastable /// True if underlying compiler uses file system to communicate source virtual SLANG_NO_THROW bool SLANG_MCALL isFileBased() = 0; - virtual SLANG_NO_THROW int SLANG_MCALL - link(const uint32_t** modules, const uint32_t* moduleSizes, - const uint32_t moduleCount, - IArtifact** outArtifact) { - SLANG_UNREFERENCED_PARAMETER(modules); - SLANG_UNREFERENCED_PARAMETER(moduleSizes); - SLANG_UNREFERENCED_PARAMETER(moduleCount); - SLANG_UNREFERENCED_PARAMETER(outArtifact); - return 0;} + virtual SLANG_NO_THROW int SLANG_MCALL link( + const uint32_t** modules, + const uint32_t* moduleSizes, + const uint32_t moduleCount, + IArtifact** outArtifact) + { + SLANG_UNREFERENCED_PARAMETER(modules); + SLANG_UNREFERENCED_PARAMETER(moduleSizes); + SLANG_UNREFERENCED_PARAMETER(moduleCount); + SLANG_UNREFERENCED_PARAMETER(outArtifact); + return 0; + } }; class DownstreamCompilerBase : public ComBaseObject, public IDownstreamCompiler diff --git a/source/compiler-core/slang-glslang-compiler.cpp b/source/compiler-core/slang-glslang-compiler.cpp index 92233e2849..540b437c5e 100644 --- a/source/compiler-core/slang-glslang-compiler.cpp +++ b/source/compiler-core/slang-glslang-compiler.cpp @@ -49,9 +49,11 @@ class GlslangDownstreamCompiler : public DownstreamCompilerBase validate(const uint32_t* contents, int contentsSize) SLANG_OVERRIDE; virtual SLANG_NO_THROW SlangResult SLANG_MCALL disassemble(const uint32_t* contents, int contentsSize) SLANG_OVERRIDE; - int link(const uint32_t** modules, const uint32_t* moduleSizes, - const uint32_t moduleCount, - IArtifact** outArtifact) SLANG_OVERRIDE; + int link( + const uint32_t** modules, + const uint32_t* moduleSizes, + const uint32_t moduleCount, + IArtifact** outArtifact) SLANG_OVERRIDE; /// Must be called before use SlangResult init(ISlangSharedLibrary* library); @@ -328,9 +330,11 @@ SlangResult GlslangDownstreamCompiler::disassemble(const uint32_t* contents, int return SLANG_FAIL; } -SlangResult GlslangDownstreamCompiler::link(const uint32_t** modules, const uint32_t* moduleSizes, - const uint32_t moduleCount, - IArtifact** outArtifact) +SlangResult GlslangDownstreamCompiler::link( + const uint32_t** modules, + const uint32_t* moduleSizes, + const uint32_t moduleCount, + IArtifact** outArtifact) { glslang_LinkRequest request; memset(&request, 0, sizeof(request)); diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h index 243b74309f..cfcbe816f3 100644 --- a/source/slang/slang-compiler.h +++ b/source/slang/slang-compiler.h @@ -1384,8 +1384,8 @@ enum class PassThroughMode : SlangPassThroughIntegral LLVM = SLANG_PASS_THROUGH_LLVM, ///< LLVM 'compiler' SpirvOpt = SLANG_PASS_THROUGH_SPIRV_OPT, ///< pass thorugh spirv to spirv-opt MetalC = SLANG_PASS_THROUGH_METAL, - Tint = SLANG_PASS_THROUGH_TINT, ///< pass through spirv to Tint API - SpirvLink = SLANG_PASS_THROUGH_SPIRV_LINK, ///< pass through spirv to spirv-link + Tint = SLANG_PASS_THROUGH_TINT, ///< pass through spirv to Tint API + SpirvLink = SLANG_PASS_THROUGH_SPIRV_LINK, ///< pass through spirv to spirv-link CountOf = SLANG_PASS_THROUGH_COUNT_OF, }; void printDiagnosticArg(StringBuilder& sb, PassThroughMode val); diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp index 422e9a14b0..94ea66d714 100644 --- a/source/slang/slang-emit.cpp +++ b/source/slang/slang-emit.cpp @@ -2134,8 +2134,7 @@ SlangResult emitSPIRVForEntryPointsDirectly( } } } - } - ); + }); SLANG_ASSERT(int(spirv.getCount()) % 4 == 0); SLANG_ASSERT(spirvFiles.getCount() == spirvSizes.getCount()); diff --git a/tools/gfx-unit-test/gfx-test-util.cpp b/tools/gfx-unit-test/gfx-test-util.cpp index c649a13173..d7cfa0f65d 100644 --- a/tools/gfx-unit-test/gfx-test-util.cpp +++ b/tools/gfx-unit-test/gfx-test-util.cpp @@ -119,7 +119,9 @@ Slang::Result loadComputeProgram( if (precompilationMode == PrecompilationMode::ExternalLink) { programDesc.downstreamLinkMode = gfx::IShaderProgram::DownstreamLinkMode::Deferred; - } else { + } + else + { programDesc.downstreamLinkMode = gfx::IShaderProgram::DownstreamLinkMode::None; } diff --git a/tools/gfx-unit-test/gfx-test-util.h b/tools/gfx-unit-test/gfx-test-util.h index 94a2d97706..3397584fc3 100644 --- a/tools/gfx-unit-test/gfx-test-util.h +++ b/tools/gfx-unit-test/gfx-test-util.h @@ -7,13 +7,13 @@ namespace gfx_test { - enum class PrecompilationMode - { - None, - SlangIR, - InternalLink, - ExternalLink, - }; +enum class PrecompilationMode +{ + None, + SlangIR, + InternalLink, + ExternalLink, +}; /// Helper function for print out diagnostic messages output by Slang compiler. void diagnoseIfNeeded(slang::IBlob* diagnosticsBlob); diff --git a/tools/gfx-unit-test/precompiled-module-2.cpp b/tools/gfx-unit-test/precompiled-module-2.cpp index c62317a07a..792f328b04 100644 --- a/tools/gfx-unit-test/precompiled-module-2.cpp +++ b/tools/gfx-unit-test/precompiled-module-2.cpp @@ -241,14 +241,18 @@ SLANG_UNIT_TEST(precompiledModule2D3D12) SLANG_UNIT_TEST(precompiledTargetModuleInternalLink2D3D12) { - runTestImpl(precompiledTargetModule2InternalLinkTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); + runTestImpl( + precompiledTargetModule2InternalLinkTestImpl, + unitTestContext, + Slang::RenderApiFlag::D3D12); } /* // Unavailable on D3D12/DXIL currently SLANG_UNIT_TEST(precompiledTargetModuleExternalLink2D3D12) { - runTestImpl(precompiledTargetModule2ExternalLinkTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); + runTestImpl(precompiledTargetModule2ExternalLinkTestImpl, unitTestContext, +Slang::RenderApiFlag::D3D12); } */ @@ -259,12 +263,18 @@ SLANG_UNIT_TEST(precompiledModule2Vulkan) SLANG_UNIT_TEST(precompiledTargetModule2InternalLinkVulkan) { - runTestImpl(precompiledTargetModule2InternalLinkTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); + runTestImpl( + precompiledTargetModule2InternalLinkTestImpl, + unitTestContext, + Slang::RenderApiFlag::Vulkan); } SLANG_UNIT_TEST(precompiledTargetModule2ExternalLinkVulkan) { - runTestImpl(precompiledTargetModule2ExternalLinkTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); + runTestImpl( + precompiledTargetModule2ExternalLinkTestImpl, + unitTestContext, + Slang::RenderApiFlag::Vulkan); } } // namespace gfx_test diff --git a/tools/gfx/vulkan/vk-shader-program.cpp b/tools/gfx/vulkan/vk-shader-program.cpp index 719be93d87..2dd9b03264 100644 --- a/tools/gfx/vulkan/vk-shader-program.cpp +++ b/tools/gfx/vulkan/vk-shader-program.cpp @@ -80,7 +80,7 @@ Result ShaderProgramImpl::createShaderModule( if (kernelCodes.getCount() == 1) { linkedKernel = kernelCodes[0]; - } + } else { linkedKernel = m_device->m_glslang.linkSPIRV(kernelCodes);