From b81e8d4c8b718e97c6d6fc65b09850f19fb80502 Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Tue, 2 Mar 2021 12:52:34 -0800 Subject: Add command-line control over SPIR-V version (#1730) * Add command-line control over SPIR-V version By default the Slang compiler policy is usually to produce output with the fewest dependencies possible. If input code can be encoded as SPIR-V 1.0, that is what we will use by default. The catch here is that in some cases later SPIR-V versions introduced improvements to the encoding that can affect performance (e.g., around large global arrays of constants), so that a user might explicitly want to require a newer SPIR-V version (restricting the driver versions their code can work on) in the hopes of seeing better performance. This change uses the system of capabilities that was previously introduced so that an option like `-profile glsl_450+spirv_1_5` can be used to explicitly request a specific SPIR-V version. Consistent with the existing implementation, the requested version will be taken as a minimum, and the final version might be higher based on other requirements (e.g., use of intrinsic functions that require a higher version). The test case included here is a little iffy in terms of long-term maintanenace. It relies on having both a `.slang` file and a `.glsl` file that we compile with the same options and then compare the SPIR-V, but that means there is no direct testing that the output SPIR-V actually uses the necessary version. If we break the inference of SPIR-V versions for both the regular and pass-through paths at once, this test won't flag the problem. A better test is probably needed soon. This change *only* adds support for controlling the SPIR-V version via capabilities specified via the command line or API. It would be nice to a future change to allow something like `[require(spirv_1_5)]` to be added to an entry point function to allow the user to embed their expectation/requirement into the source code. * fixup: clang warning --- source/core/slang-random-generator.cpp | 2 +- source/slang/slang-capability-defs.h | 17 +++++---- source/slang/slang-compiler.cpp | 57 ++++++++++++++++++++++------- source/slang/slang-emit.cpp | 6 +++ tests/spirv/spirv-version-option.slang | 14 +++++++ tests/spirv/spirv-version-option.slang.glsl | 11 ++++++ 6 files changed, 85 insertions(+), 22 deletions(-) create mode 100644 tests/spirv/spirv-version-option.slang create mode 100644 tests/spirv/spirv-version-option.slang.glsl diff --git a/source/core/slang-random-generator.cpp b/source/core/slang-random-generator.cpp index ec06336f1..315678f0a 100644 --- a/source/core/slang-random-generator.cpp +++ b/source/core/slang-random-generator.cpp @@ -8,7 +8,7 @@ namespace Slang { float RandomGenerator::nextUnitFloat32() { int32_t intValue = nextInt32(); - return (intValue & 0x7fffffff) * (1.0f / 0x7fffffff); + return (intValue & 0x7fffffff) * (1.0f / float(0x7fffffff)); } bool RandomGenerator::nextBool() diff --git a/source/slang/slang-capability-defs.h b/source/slang/slang-capability-defs.h index 003fd3125..f66add15b 100644 --- a/source/slang/slang-capability-defs.h +++ b/source/slang/slang-capability-defs.h @@ -56,15 +56,18 @@ SLANG_CAPABILITY_ATOM0(C, c, Concrete,TargetFormat,0) SLANG_CAPABILITY_ATOM0(CPP, cpp, Concrete,TargetFormat,0) SLANG_CAPABILITY_ATOM0(CUDA, cuda, Concrete,TargetFormat,0) -// TODO: We should have multiple capabilities for the various SPIR-V versions, +// We have multiple capabilities for the various SPIR-V versions, // arranged so that they inherit from one another to represent which versions -// provide a super-set of the features of earlier ones (e.g., SPIR-V 1.4 should -// be expressed as inheriting from SPIR-V 1.3). +// provide a super-set of the features of earlier ones (e.g., SPIR-V 1.4 is +// expressed as inheriting from SPIR-V 1.3). // -// For now we are only including the version(s) that are relevant to the -// features controlled by the capability system. -// -SLANG_CAPABILITY_ATOM1(SPIRV_1_4, spirv_1_4, Concrete,None,0, GLSL) +SLANG_CAPABILITY_ATOM1(SPIRV, __spirv, Abstract,None,0, GLSL) +SLANG_CAPABILITY_ATOM1(SPIRV_1_0, spirv_1_0, Concrete,None,0, SPIRV) +SLANG_CAPABILITY_ATOM1(SPIRV_1_1, spirv_1_1, Concrete,None,0, SPIRV_1_0) +SLANG_CAPABILITY_ATOM1(SPIRV_1_2, spirv_1_2, Concrete,None,0, SPIRV_1_1) +SLANG_CAPABILITY_ATOM1(SPIRV_1_3, spirv_1_3, Concrete,None,0, SPIRV_1_2) +SLANG_CAPABILITY_ATOM1(SPIRV_1_4, spirv_1_4, Concrete,None,0, SPIRV_1_3) +SLANG_CAPABILITY_ATOM1(SPIRV_1_5, spirv_1_5, Concrete,None,0, SPIRV_1_4) // The following capabilities all pertain to how ray tracing shaders are translated // to GLSL, where there are two different extensions that can provide the core diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp index 993a4966e..2d0287613 100755 --- a/source/slang/slang-compiler.cpp +++ b/source/slang/slang-compiler.cpp @@ -577,6 +577,45 @@ namespace Slang outCodeBuilder << fileContent << "\n"; } + static void _maybeCreatePassThroughExtensionTracker( + CodeGenTarget target, + EndToEndCompileRequest* endToEndReq, + SourceResult& outSource) + { + if(!isPassThroughEnabled(endToEndReq)) + return; + + if(target != CodeGenTarget::GLSL) + return; + + if(outSource.extensionTracker) + return; + + RefPtr extensionTracker = new GLSLExtensionTracker(); + outSource.extensionTracker = extensionTracker; + } + + void trackGLSLTargetCaps( + GLSLExtensionTracker* extensionTracker, + CapabilitySet const& caps) + { + for( auto atom : caps.getExpandedAtoms() ) + { + switch( atom ) + { + default: + break; + + case CapabilityAtom::SPIRV_1_0: extensionTracker->requireSPIRVVersion(SemanticVersion(1, 0)); break; + case CapabilityAtom::SPIRV_1_1: extensionTracker->requireSPIRVVersion(SemanticVersion(1, 1)); break; + case CapabilityAtom::SPIRV_1_2: extensionTracker->requireSPIRVVersion(SemanticVersion(1, 2)); break; + case CapabilityAtom::SPIRV_1_3: extensionTracker->requireSPIRVVersion(SemanticVersion(1, 3)); break; + case CapabilityAtom::SPIRV_1_4: extensionTracker->requireSPIRVVersion(SemanticVersion(1, 4)); break; + case CapabilityAtom::SPIRV_1_5: extensionTracker->requireSPIRVVersion(SemanticVersion(1, 5)); break; + } + } + } + SlangResult emitEntryPointsSource( BackEndCompileRequest* compileRequest, const List& entryPointIndices, @@ -602,6 +641,10 @@ namespace Slang StringBuilder codeBuilder; if (target == CodeGenTarget::GLSL) { + _maybeCreatePassThroughExtensionTracker(target, endToEndReq, outSource); + if(auto extensionTracker = as(outSource.extensionTracker)) + trackGLSLTargetCaps(extensionTracker, targetReq->getTargetCaps()); + // Special case GLSL int translationUnitCounter = 0; for (auto sourceFile : translationUnit->getSourceFiles()) @@ -1633,20 +1676,6 @@ SlangResult dissassembleDXILUsingDXC( request.spirvVersion.minor = spirvLanguageVersion.m_minor; request.spirvVersion.patch = spirvLanguageVersion.m_patch; } - else - { - // HACK: look at the requested capabilities of the target, - // and see if they specify a SPIR-V version that we should - // pass down. - // - auto targetCaps = targetReq->getTargetCaps(); - if(targetCaps.implies(CapabilityAtom::SPIRV_1_4)) - { - request.spirvVersion.major = 1; - request.spirvVersion.minor = 4; - request.spirvVersion.patch = 0; - } - } request.outputFunc = outputFunc; request.outputUserData = &spirvOut; diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp index dc4709d11..c97412cf0 100644 --- a/source/slang/slang-emit.cpp +++ b/source/slang/slang-emit.cpp @@ -696,6 +696,10 @@ Result linkAndOptimizeIR( return SLANG_OK; } +void trackGLSLTargetCaps( + GLSLExtensionTracker* extensionTracker, + CapabilitySet const& caps); + SlangResult emitEntryPointsSourceFromIR( BackEndCompileRequest* compileRequest, const List& entryPointIndices, @@ -844,6 +848,8 @@ SlangResult emitEntryPointsSourceFromIR( if (auto glslExtensionTracker = as(extensionTracker)) { + trackGLSLTargetCaps(glslExtensionTracker, targetRequest->getTargetCaps()); + StringBuilder builder; glslExtensionTracker->appendExtensionRequireLines(builder); sourceWriter.emit(builder.getUnownedSlice()); diff --git a/tests/spirv/spirv-version-option.slang b/tests/spirv/spirv-version-option.slang new file mode 100644 index 000000000..75f817385 --- /dev/null +++ b/tests/spirv/spirv-version-option.slang @@ -0,0 +1,14 @@ +// spirv-version-option.slang + +// Test for command-line options to control SPIR-V version used. + +//TEST:CROSS_COMPILE:-target spirv -profile glsl_450 -entry main -stage compute +//TEST:CROSS_COMPILE:-target spirv -profile glsl_450+spirv_1_1 -entry main -stage compute +//TEST:CROSS_COMPILE:-target spirv -profile glsl_450+spirv_1_2 -entry main -stage compute +//TEST:CROSS_COMPILE:-target spirv -profile glsl_450+spirv_1_3 -entry main -stage compute +//TEST:CROSS_COMPILE:-target spirv -profile glsl_450+spirv_1_4 -entry main -stage compute +//TEST:CROSS_COMPILE:-target spirv -profile glsl_450+spirv_1_5 -entry main -stage compute + +[shader("compute")] +void main() +{} \ No newline at end of file diff --git a/tests/spirv/spirv-version-option.slang.glsl b/tests/spirv/spirv-version-option.slang.glsl new file mode 100644 index 000000000..8cd781a42 --- /dev/null +++ b/tests/spirv/spirv-version-option.slang.glsl @@ -0,0 +1,11 @@ +// spirv-version-option.slang.glsl +//TEST_IGNORE_FILE: + +#version 450 + +layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; + +void main() +{ + return; +} -- cgit v1.2.3