summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Panteleev <alpanteleev@nvidia.com>2022-05-18 10:57:37 -0700
committerGitHub <noreply@github.com>2022-05-18 10:57:37 -0700
commit69cb6e8f300d77e74bd2c7dfe15d12e10b38f512 (patch)
treec2d23f2883acb28407106a096b55c64111f098b1
parent1148564b9cdbbc8fec4fbecf65b0af60aa6af344 (diff)
Support for querying which parameters are used in emitted code (#2239)
See https://github.com/shader-slang/slang/issues/2213
-rw-r--r--build/visual-studio/slang/slang.vcxproj3
-rw-r--r--build/visual-studio/slang/slang.vcxproj.filters9
-rw-r--r--slang.h26
-rw-r--r--source/slang/slang-api.cpp7
-rw-r--r--source/slang/slang-compiler.cpp56
-rwxr-xr-xsource/slang/slang-compiler.h115
-rw-r--r--source/slang/slang-emit.cpp14
-rw-r--r--source/slang/slang-ir-collect-global-uniforms.cpp36
-rw-r--r--source/slang/slang-ir-link.h1
-rw-r--r--source/slang/slang-ir-metadata.cpp77
-rw-r--r--source/slang/slang-ir-metadata.h12
-rw-r--r--source/slang/slang-reflection-api.cpp14
-rw-r--r--source/slang/slang.cpp15
-rw-r--r--tests/cross-compile/cpp-resource-reflection.slang2
-rw-r--r--tests/cuda/cuda-reflection.slang2
-rw-r--r--tests/hlsl-intrinsic/sampler-feedback/sampler-feedback-basic.slang2
-rw-r--r--tests/ir/string-literal-hash-reflection.slang2
-rw-r--r--tests/reflection/arrays.hlsl2
-rw-r--r--tests/reflection/attribute.slang2
-rw-r--r--tests/reflection/binding-gl.hlsl2
-rw-r--r--tests/reflection/binding-push-constant-gl.hlsl2
-rw-r--r--tests/reflection/buffer-layout.slang4
-rw-r--r--tests/reflection/cross-compile.slang2
-rw-r--r--tests/reflection/default-space.slang2
-rw-r--r--tests/reflection/explicit-register-space.slang2
-rw-r--r--tests/reflection/matrix-layout.slang4
-rw-r--r--tests/reflection/mix-explicit-and-implicit-spaces.slang2
-rw-r--r--tests/reflection/multi-file.hlsl2
-rw-r--r--tests/reflection/parameter-block-explicit-space.slang2
-rw-r--r--tests/reflection/parameter-block.slang6
-rw-r--r--tests/reflection/reflect-imported-code.hlsl2
-rw-r--r--tests/reflection/reflect-static.slang2
-rw-r--r--tests/reflection/reflection0.hlsl2
-rw-r--r--tests/reflection/resource-in-cbuffer.hlsl2
-rw-r--r--tests/reflection/sample-index-input.hlsl2
-rw-r--r--tests/reflection/sample-rate-input.hlsl2
-rw-r--r--tests/reflection/shared-modifier.hlsl2
-rw-r--r--tests/reflection/structured-buffer.slang2
-rw-r--r--tests/reflection/thread-group-size.hlsl2
-rw-r--r--tests/reflection/unbounded-arrays.hlsl2
-rw-r--r--tests/reflection/used-parameters.slang52
-rw-r--r--tests/reflection/used-parameters.slang.expected350
-rw-r--r--tests/reflection/vertex-input-semantics.hlsl2
-rw-r--r--tools/slang-reflection-test/slang-reflection-test-main.cpp83
44 files changed, 843 insertions, 91 deletions
diff --git a/build/visual-studio/slang/slang.vcxproj b/build/visual-studio/slang/slang.vcxproj
index 49ed81173..267b25098 100644
--- a/build/visual-studio/slang/slang.vcxproj
+++ b/build/visual-studio/slang/slang.vcxproj
@@ -335,6 +335,7 @@ IF EXIST ..\..\..\external\slang-binaries\bin\windows-aarch64\slang-glslang.dll\
<ClInclude Include="..\..\..\source\slang\slang-emit-hlsl.h" />
<ClInclude Include="..\..\..\source\slang\slang-emit-precedence.h" />
<ClInclude Include="..\..\..\source\slang\slang-emit-source-writer.h" />
+ <ClInclude Include="..\..\..\source\slang\slang-emit.h" />
<ClInclude Include="..\..\..\source\slang\slang-glsl-extension-tracker.h" />
<ClInclude Include="..\..\..\source\slang\slang-hlsl-intrinsic-set.h" />
<ClInclude Include="..\..\..\source\slang\slang-image-format-defs.h" />
@@ -376,6 +377,7 @@ IF EXIST ..\..\..\external\slang-binaries\bin\windows-aarch64\slang-glslang.dll\
<ClInclude Include="..\..\..\source\slang\slang-ir-lower-generics.h" />
<ClInclude Include="..\..\..\source\slang\slang-ir-lower-reinterpret.h" />
<ClInclude Include="..\..\..\source\slang\slang-ir-lower-tuple-types.h" />
+ <ClInclude Include="..\..\..\source\slang\slang-ir-metadata.h" />
<ClInclude Include="..\..\..\source\slang\slang-ir-missing-return.h" />
<ClInclude Include="..\..\..\source\slang\slang-ir-optix-entry-point-uniforms.h" />
<ClInclude Include="..\..\..\source\slang\slang-ir-restructure-scoping.h" />
@@ -517,6 +519,7 @@ IF EXIST ..\..\..\external\slang-binaries\bin\windows-aarch64\slang-glslang.dll\
<ClCompile Include="..\..\..\source\slang\slang-ir-lower-generics.cpp" />
<ClCompile Include="..\..\..\source\slang\slang-ir-lower-reinterpret.cpp" />
<ClCompile Include="..\..\..\source\slang\slang-ir-lower-tuple-types.cpp" />
+ <ClCompile Include="..\..\..\source\slang\slang-ir-metadata.cpp" />
<ClCompile Include="..\..\..\source\slang\slang-ir-missing-return.cpp" />
<ClCompile Include="..\..\..\source\slang\slang-ir-optix-entry-point-uniforms.cpp" />
<ClCompile Include="..\..\..\source\slang\slang-ir-restructure-scoping.cpp" />
diff --git a/build/visual-studio/slang/slang.vcxproj.filters b/build/visual-studio/slang/slang.vcxproj.filters
index d6cebe52a..18f5495a7 100644
--- a/build/visual-studio/slang/slang.vcxproj.filters
+++ b/build/visual-studio/slang/slang.vcxproj.filters
@@ -102,6 +102,9 @@
<ClInclude Include="..\..\..\source\slang\slang-emit-source-writer.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="..\..\..\source\slang\slang-emit.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
<ClInclude Include="..\..\..\source\slang\slang-glsl-extension-tracker.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -225,6 +228,9 @@
<ClInclude Include="..\..\..\source\slang\slang-ir-lower-tuple-types.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="..\..\..\source\slang\slang-ir-metadata.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
<ClInclude Include="..\..\..\source\slang\slang-ir-missing-return.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -644,6 +650,9 @@
<ClCompile Include="..\..\..\source\slang\slang-ir-lower-tuple-types.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\..\..\source\slang\slang-ir-metadata.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="..\..\..\source\slang\slang-ir-missing-return.cpp">
<Filter>Source Files</Filter>
</ClCompile>
diff --git a/slang.h b/slang.h
index a2623bdd3..d08c6be34 100644
--- a/slang.h
+++ b/slang.h
@@ -1355,6 +1355,10 @@ extern "C"
SlangCompileRequest* request,
SlangCompileFlags flags);
+ /*! @see slang::ICompileRequest::getCompileFlags */
+ SLANG_API SlangCompileFlags spGetCompileFlags(
+ SlangCompileRequest* request);
+
/*! @see slang::ICompileRequest::setDumpIntermediates */
SLANG_API void spSetDumpIntermediates(
SlangCompileRequest* request,
@@ -2147,6 +2151,15 @@ extern "C"
SLANG_API unsigned spReflectionParameter_GetBindingIndex(SlangReflectionParameter* parameter);
SLANG_API unsigned spReflectionParameter_GetBindingSpace(SlangReflectionParameter* parameter);
+ SLANG_API SlangResult spIsParameterLocationUsed(
+ SlangCompileRequest* request,
+ SlangInt entryPointIndex,
+ SlangInt targetIndex,
+ SlangParameterCategory category, // is this a `t` register? `s` register?
+ SlangUInt spaceIndex, // `space` for D3D12, `set` for Vulkan
+ SlangUInt registerIndex, // `register` for D3D12, `binding` for Vulkan
+ bool& outUsed);
+
// Entry Point Reflection
SLANG_API char const* spReflectionEntryPoint_getName(
@@ -3371,6 +3384,11 @@ namespace slang
SlangCompileFlags flags) = 0;
/*!
+ @brief Returns the compilation flags previously set with `setCompileFlags`
+ */
+ virtual SLANG_NO_THROW SlangCompileFlags SLANG_MCALL getCompileFlags() = 0;
+
+ /*!
@brief Set whether to dump intermediate results (for debugging) or not.
*/
virtual SLANG_NO_THROW void SLANG_MCALL setDumpIntermediates(
@@ -3892,6 +3910,14 @@ namespace slang
virtual SLANG_NO_THROW SlangResult SLANG_MCALL getProgramWithEntryPoints(
slang::IComponentType** outProgram) = 0;
+ virtual SLANG_NO_THROW SlangResult SLANG_MCALL isParameterLocationUsed(
+ SlangInt entryPointIndex,
+ SlangInt targetIndex,
+ SlangParameterCategory category,
+ SlangUInt spaceIndex,
+ SlangUInt registerIndex,
+ bool& outUsed) = 0;
+
/** Set the line directive mode for a target.
*/
virtual SLANG_NO_THROW void SLANG_MCALL setTargetLineDirectiveMode(
diff --git a/source/slang/slang-api.cpp b/source/slang/slang-api.cpp
index 911bd0f0f..50986660b 100644
--- a/source/slang/slang-api.cpp
+++ b/source/slang/slang-api.cpp
@@ -245,6 +245,13 @@ SLANG_API void spSetCompileFlags(
request->setCompileFlags(flags);
}
+SLANG_API SlangCompileFlags spGetCompileFlags(
+ slang::ICompileRequest* request)
+{
+ SLANG_ASSERT(request);
+ return request->getCompileFlags();
+}
+
SLANG_API void spSetDumpIntermediates(
slang::ICompileRequest* request,
int enable)
diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp
index 7988af3e8..74162d2ef 100644
--- a/source/slang/slang-compiler.cpp
+++ b/source/slang/slang-compiler.cpp
@@ -143,6 +143,28 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val)
return SLANG_OK;
}
+ SlangResult CompileResult::isParameterLocationUsed(SlangParameterCategory category, UInt spaceIndex, UInt registerIndex, bool& outUsed)
+ {
+ if (!postEmitMetadata)
+ return SLANG_E_NOT_AVAILABLE;
+
+ if (!ShaderBindingRange::isUsageTracked((slang::ParameterCategory)category))
+ return SLANG_E_NOT_AVAILABLE;
+
+ // TODO: optimize this with a binary search through a sorted list
+ for (const auto& range : postEmitMetadata->usedBindings)
+ {
+ if (range.containsBinding((slang::ParameterCategory)category, spaceIndex, registerIndex))
+ {
+ outUsed = true;
+ return SLANG_OK;
+ }
+ }
+
+ outUsed = false;
+ return SLANG_OK;
+ }
+
//
// FrontEndEntryPointRequest
//
@@ -662,7 +684,8 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val)
}
SlangResult CodeGenContext::emitEntryPointsSource(
- String& outSource)
+ String& outSource,
+ RefPtr<PostEmitMetadata>& outMetadata)
{
outSource = String();
@@ -714,7 +737,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val)
else
{
return emitEntryPointsSourceFromIR(
- outSource);
+ outSource, outMetadata);
}
}
@@ -985,7 +1008,8 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val)
}
SlangResult CodeGenContext::emitWithDownstreamForEntryPoints(
- RefPtr<DownstreamCompileResult>& outResult)
+ RefPtr<DownstreamCompileResult>& outResult,
+ RefPtr<PostEmitMetadata>& outMetadata)
{
outResult.setNull();
@@ -1127,7 +1151,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val)
options.sourceContentsPath = calcSourcePathForEntryPoints();
CodeGenContext sourceCodeGenContext(this, sourceTarget, extensionTracker);
- SLANG_RETURN_ON_FAIL(sourceCodeGenContext.emitEntryPointsSource(options.sourceContents));
+ SLANG_RETURN_ON_FAIL(sourceCodeGenContext.emitEntryPointsSource(options.sourceContents, outMetadata));
}
else
{
@@ -1144,7 +1168,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val)
else
{
CodeGenContext sourceCodeGenContext(this, sourceTarget, extensionTracker);
- SLANG_RETURN_ON_FAIL(sourceCodeGenContext.emitEntryPointsSource(options.sourceContents));
+ SLANG_RETURN_ON_FAIL(sourceCodeGenContext.emitEntryPointsSource(options.sourceContents, outMetadata));
sourceCodeGenContext.maybeDumpIntermediate(options.sourceContents.getBuffer());
sourceLanguage = (SourceLanguage)TypeConvertUtil::getSourceLanguageFromTarget((SlangCompileTarget)sourceTarget);
@@ -1504,7 +1528,8 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val)
SlangResult emitSPIRVForEntryPointsDirectly(
CodeGenContext* codeGenContext,
- List<uint8_t>& spirvOut);
+ List<uint8_t>& spirvOut,
+ RefPtr<PostEmitMetadata>& outMetadata);
static CodeGenTarget _getIntermediateTarget(CodeGenTarget target)
{
@@ -1519,7 +1544,8 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val)
/// Function to simplify the logic around emitting, and dissassembling
SlangResult CodeGenContext::_emitEntryPoints(
- RefPtr<DownstreamCompileResult>& outDownstreamResult)
+ RefPtr<DownstreamCompileResult>& outDownstreamResult,
+ RefPtr<PostEmitMetadata>& outMetadata)
{
auto target = getTargetFormat();
switch (target)
@@ -1533,7 +1559,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val)
CodeGenContext intermediateContext(this, intermediateTarget);
RefPtr<DownstreamCompileResult> code;
- SLANG_RETURN_ON_FAIL(intermediateContext._emitEntryPoints(code));
+ SLANG_RETURN_ON_FAIL(intermediateContext._emitEntryPoints(code, outMetadata));
intermediateContext.maybeDumpIntermediate(code);
// Then disassemble the intermediate binary result to get the desired output
@@ -1548,7 +1574,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val)
if (getTargetReq()->shouldEmitSPIRVDirectly())
{
List<uint8_t> spirv;
- SLANG_RETURN_ON_FAIL(emitSPIRVForEntryPointsDirectly(this, spirv));
+ SLANG_RETURN_ON_FAIL(emitSPIRVForEntryPointsDirectly(this, spirv, outMetadata));
auto spirvBlob = ListBlob::moveCreate(spirv);
outDownstreamResult = new BlobDownstreamCompileResult(DownstreamDiagnostics(), spirvBlob);
return SLANG_OK;
@@ -1560,7 +1586,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val)
case CodeGenTarget::ShaderHostCallable:
case CodeGenTarget::ShaderSharedLibrary:
case CodeGenTarget::HostExecutable:
- SLANG_RETURN_ON_FAIL(emitWithDownstreamForEntryPoints(outDownstreamResult));
+ SLANG_RETURN_ON_FAIL(emitWithDownstreamForEntryPoints(outDownstreamResult, outMetadata));
return SLANG_OK;
default: break;
@@ -1590,11 +1616,12 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val)
case CodeGenTarget::HostExecutable:
{
RefPtr<DownstreamCompileResult> downstreamResult;
+ RefPtr<PostEmitMetadata> metadata;
- if (SLANG_SUCCEEDED(_emitEntryPoints(downstreamResult)))
+ if (SLANG_SUCCEEDED(_emitEntryPoints(downstreamResult, metadata)))
{
maybeDumpIntermediate(downstreamResult);
- result = CompileResult(downstreamResult);
+ result = CompileResult(downstreamResult, metadata);
}
}
break;
@@ -1606,17 +1633,18 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val)
case CodeGenTarget::CSource:
{
RefPtr<ExtensionTracker> extensionTracker = _newExtensionTracker(target);
+ RefPtr<PostEmitMetadata> metadata;
CodeGenContext subContext(this, target, extensionTracker);
String code;
- if (SLANG_FAILED(subContext.emitEntryPointsSource(code)))
+ if (SLANG_FAILED(subContext.emitEntryPointsSource(code, metadata)))
{
return result;
}
subContext.maybeDumpIntermediate(code.getBuffer());
- result = CompileResult(code);
+ result = CompileResult(code, metadata);
}
break;
diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h
index 39ee830d2..e0152566c 100755
--- a/source/slang/slang-compiler.h
+++ b/source/slang/slang-compiler.h
@@ -141,26 +141,117 @@ namespace Slang
class Module;
class TranslationUnitRequest;
+ struct ShaderBindingRange
+ {
+ slang::ParameterCategory category = slang::ParameterCategory::None;
+ UInt spaceIndex = 0;
+ UInt registerIndex = 0;
+ UInt registerCount = 0; // 0 for unsized
+
+ bool isInfinite() const
+ {
+ return registerCount == 0;
+ }
+
+ bool containsBinding(slang::ParameterCategory _category, UInt _spaceIndex, UInt _registerIndex) const
+ {
+ return category == _category
+ && spaceIndex == _spaceIndex
+ && registerIndex <= _registerIndex
+ && (isInfinite() || registerCount + registerIndex > _registerIndex);
+ }
+
+ bool intersectsWith(const ShaderBindingRange& other) const
+ {
+ if (category != other.category || spaceIndex != other.spaceIndex)
+ return false;
+
+ const bool leftIntersection = (registerIndex < other.registerIndex + other.registerCount) || other.isInfinite();
+ const bool rightIntersection = (other.registerIndex < registerIndex + registerCount) || isInfinite();
+
+ return leftIntersection && rightIntersection;
+ }
+
+ bool adjacentTo(const ShaderBindingRange& other) const
+ {
+ if (category != other.category || spaceIndex != other.spaceIndex)
+ return false;
+
+ const bool leftIntersection = (registerIndex <= other.registerIndex + other.registerCount) || other.isInfinite();
+ const bool rightIntersection = (other.registerIndex <= registerIndex + registerCount) || isInfinite();
+
+ return leftIntersection && rightIntersection;
+ }
+
+ void mergeWith(const ShaderBindingRange other)
+ {
+ UInt newRegisterIndex = Math::Min(registerIndex, other.registerIndex);
+
+ if (other.isInfinite())
+ registerCount = 0;
+ else if (!isInfinite())
+ registerCount = Math::Max(registerIndex + registerCount, other.registerIndex + other.registerCount) - newRegisterIndex;
+
+ registerIndex = newRegisterIndex;
+ }
+
+ static bool isUsageTracked(slang::ParameterCategory category)
+ {
+ switch(category)
+ {
+ case slang::ConstantBuffer:
+ case slang::ShaderResource:
+ case slang::UnorderedAccess:
+ case slang::SamplerState:
+ return true;
+ default:
+ return false;
+ }
+ }
+ };
+
+ struct PostEmitMetadata : public RefObject
+ {
+ List<ShaderBindingRange> usedBindings;
+ };
+
// Result of compiling an entry point.
// Should only ever be string, binary or shared library
class CompileResult
{
public:
CompileResult() = default;
- explicit CompileResult(String const& str) : format(ResultFormat::Text), outputString(str) {}
- explicit CompileResult(ISlangBlob* inBlob) : format(ResultFormat::Binary), blob(inBlob) {}
- explicit CompileResult(DownstreamCompileResult* inDownstreamResult): format(ResultFormat::Binary), downstreamResult(inDownstreamResult) {}
- explicit CompileResult(const UnownedStringSlice& slice ) : format(ResultFormat::Text), outputString(slice) {}
+ explicit CompileResult(String const& str, RefPtr<PostEmitMetadata> metadata)
+ : format(ResultFormat::Text)
+ , outputString(str)
+ , postEmitMetadata(metadata) {}
+
+ explicit CompileResult(ISlangBlob* inBlob)
+ : format(ResultFormat::Binary)
+ , blob(inBlob) {}
+
+ explicit CompileResult(DownstreamCompileResult* inDownstreamResult, RefPtr<PostEmitMetadata> metadata)
+ : format(ResultFormat::Binary)
+ , downstreamResult(inDownstreamResult)
+ , postEmitMetadata(metadata) {}
+
+ explicit CompileResult(const UnownedStringSlice& slice )
+ : format(ResultFormat::Text)
+ , outputString(slice) {}
SlangResult getBlob(ComPtr<ISlangBlob>& outBlob) const;
SlangResult getSharedLibrary(ComPtr<ISlangSharedLibrary>& outSharedLibrary);
+ SlangResult isParameterLocationUsed(SlangParameterCategory category, UInt spaceIndex, UInt registerIndex, bool& outUsed);
+
ResultFormat format = ResultFormat::None;
String outputString; ///< Only set if result type is ResultFormat::Text
mutable ComPtr<ISlangBlob> blob;
RefPtr<DownstreamCompileResult> downstreamResult;
+
+ RefPtr<PostEmitMetadata> postEmitMetadata;
};
/// Information collected about global or entry-point shader parameters
@@ -939,7 +1030,7 @@ namespace Slang
Index getShaderParamCount() SLANG_OVERRIDE { return 0; }
ShaderParamInfo getShaderParam(Index index) SLANG_OVERRIDE { SLANG_UNUSED(index); return ShaderParamInfo(); }
-
+
class EntryPointSpecializationInfo : public SpecializationInfo
{
public:
@@ -2428,13 +2519,16 @@ namespace Slang
/* Emits entry point source taking into account if a pass-through or not. Uses 'targetFormat' to determine
the target (not targetReq) */
SlangResult emitEntryPointsSource(
- String& outSource);
+ String& outSource,
+ RefPtr<PostEmitMetadata>& outMetadata);
SlangResult emitEntryPointsSourceFromIR(
- String& outSource);
+ String& outSource,
+ RefPtr<PostEmitMetadata>& outMetadata);
SlangResult emitWithDownstreamForEntryPoints(
- RefPtr<DownstreamCompileResult>& outResult);
+ RefPtr<DownstreamCompileResult>& outResult,
+ RefPtr<PostEmitMetadata>& outMetadata);
/* Determines a suitable filename to identify the input for a given entry point being compiled.
If the end-to-end compile is a pass-through case, will attempt to find the (unique) source file
@@ -2450,7 +2544,8 @@ namespace Slang
SlangResult _emitEntryPoints(
- RefPtr<DownstreamCompileResult>& outDownstreamResult);
+ RefPtr<DownstreamCompileResult>& outDownstreamResult,
+ RefPtr<PostEmitMetadata>& outMetadata);
private:
Shared* m_shared = nullptr;
@@ -2477,6 +2572,7 @@ namespace Slang
// slang::ICompileRequest
virtual SLANG_NO_THROW void SLANG_MCALL setFileSystem(ISlangFileSystem* fileSystem) SLANG_OVERRIDE;
virtual SLANG_NO_THROW void SLANG_MCALL setCompileFlags(SlangCompileFlags flags) SLANG_OVERRIDE;
+ virtual SLANG_NO_THROW SlangCompileFlags SLANG_MCALL getCompileFlags() SLANG_OVERRIDE;
virtual SLANG_NO_THROW void SLANG_MCALL setDumpIntermediates(int enable) SLANG_OVERRIDE;
virtual SLANG_NO_THROW void SLANG_MCALL setDumpIntermediatePrefix(const char* prefix) SLANG_OVERRIDE;
virtual SLANG_NO_THROW void SLANG_MCALL setLineDirectiveMode(SlangLineDirectiveMode mode) SLANG_OVERRIDE;
@@ -2536,6 +2632,7 @@ namespace Slang
virtual SLANG_NO_THROW void SLANG_MCALL setCommandLineCompilerMode() SLANG_OVERRIDE;
virtual SLANG_NO_THROW SlangResult SLANG_MCALL addTargetCapability(SlangInt targetIndex, SlangCapabilityID capability) SLANG_OVERRIDE;
virtual SLANG_NO_THROW SlangResult SLANG_MCALL getProgramWithEntryPoints(slang::IComponentType** outProgram) SLANG_OVERRIDE;
+ virtual SLANG_NO_THROW SlangResult SLANG_MCALL isParameterLocationUsed(SlangInt entryPointIndex, SlangInt targetIndex, SlangParameterCategory category, SlangUInt spaceIndex, SlangUInt registerIndex, bool& outUsed) SLANG_OVERRIDE;
virtual SLANG_NO_THROW void SLANG_MCALL setTargetLineDirectiveMode(
SlangInt targetIndex,
SlangLineDirectiveMode mode) SLANG_OVERRIDE;
diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp
index d231acf14..a128644d3 100644
--- a/source/slang/slang-emit.cpp
+++ b/source/slang/slang-emit.cpp
@@ -25,6 +25,7 @@
#include "slang-ir-lower-tuple-types.h"
#include "slang-ir-lower-bit-cast.h"
#include "slang-ir-lower-reinterpret.h"
+#include "slang-ir-metadata.h"
#include "slang-ir-optix-entry-point-uniforms.h"
#include "slang-ir-restructure.h"
#include "slang-ir-restructure-scoping.h"
@@ -818,11 +819,15 @@ Result linkAndOptimizeIR(
#endif
validateIRModuleIfEnabled(codeGenContext, irModule);
+ outLinkedIR.metadata = new PostEmitMetadata();
+ collectMetadata(irModule, *outLinkedIR.metadata);
+
return SLANG_OK;
}
SlangResult CodeGenContext::emitEntryPointsSourceFromIR(
- String& outSource)
+ String& outSource,
+ RefPtr<PostEmitMetadata>& outMetadata)
{
outSource = String();
@@ -927,6 +932,8 @@ SlangResult CodeGenContext::emitEntryPointsSourceFromIR(
auto irModule = linkedIR.module;
+ outMetadata = linkedIR.metadata;
+
// After all of the required optimization and legalization
// passes have been performed, we can emit target code from
// the IR module.
@@ -1007,7 +1014,8 @@ SlangResult emitSPIRVFromIR(
SlangResult emitSPIRVForEntryPointsDirectly(
CodeGenContext* codeGenContext,
- List<uint8_t>& spirvOut)
+ List<uint8_t>& spirvOut,
+ RefPtr<PostEmitMetadata>& outMetadata)
{
// Outside because we want to keep IR in scope whilst we are processing emits
LinkedIR linkedIR;
@@ -1022,6 +1030,8 @@ SlangResult emitSPIRVForEntryPointsDirectly(
emitSPIRVFromIR(codeGenContext, irModule, irEntryPoints, spirvOut);
+ outMetadata = linkedIR.metadata;
+
return SLANG_OK;
}
diff --git a/source/slang/slang-ir-collect-global-uniforms.cpp b/source/slang/slang-ir-collect-global-uniforms.cpp
index 88ebe9940..87b21c819 100644
--- a/source/slang/slang-ir-collect-global-uniforms.cpp
+++ b/source/slang/slang-ir-collect-global-uniforms.cpp
@@ -172,19 +172,6 @@ struct CollectGlobalUniformParametersContext
auto globalParamLayout = fieldLayoutAttr->getLayout();
- // If the given parameter doesn't contribute to uniform/ordinary usage, then
- // we can safely leave it at the global scope and potentially avoid a lot
- // of complications that might otherwise arise (that is, we don't need to worry
- // about downstream passes that might have worked for a simple global parameter,
- // but that would not work for one nested inside a structure.
- //
- // TODO: It would be more consistent and robust to *always* wrap up
- // these global parameters appropriately, and ensure that all the downstream
- // passes can handle that case, since they would need to do so in general.
- //
- if(!globalParamLayout->getTypeLayout()->findSizeAttr(LayoutResourceKind::Uniform) )
- continue;
-
// Once we have decided to do replacement, we need to
// set ourselves up to emit the replacement code.
//
@@ -195,11 +182,6 @@ struct CollectGlobalUniformParametersContext
//
auto fieldKey = builder->createStructKey();
- // The new structure field will need to have whatever decorations
- // had been put on the global parameter (notably including any name hint)
- //
- globalParam->transferDecorationsTo(fieldKey);
-
// In order to make sure that the existing IR layout information for
// the global scope remains valid, we will swap out the key in the
// per-field layout information to reference the key we created
@@ -207,6 +189,24 @@ struct CollectGlobalUniformParametersContext
//
fieldLayoutAttr->setOperand(0, fieldKey);
+ // If the given parameter doesn't contribute to uniform/ordinary usage, then
+ // we can safely leave it at the global scope and potentially avoid a lot
+ // of complications that might otherwise arise (that is, we don't need to worry
+ // about downstream passes that might have worked for a simple global parameter,
+ // but that would not work for one nested inside a structure.
+ //
+ // TODO: It would be more consistent and robust to *always* wrap up
+ // these global parameters appropriately, and ensure that all the downstream
+ // passes can handle that case, since they would need to do so in general.
+ //
+ if (!globalParamLayout->getTypeLayout()->findSizeAttr(LayoutResourceKind::Uniform))
+ continue;
+
+ // The new structure field will need to have whatever decorations
+ // had been put on the global parameter (notably including any name hint)
+ //
+ globalParam->transferDecorationsTo(fieldKey);
+
// Now we can add a field to the `GlobalParams` type that
// will stand in for the parameter: it will have the key we
// just generated, and the type of the original parameter.
diff --git a/source/slang/slang-ir-link.h b/source/slang/slang-ir-link.h
index 6c81ae734..798013a8d 100644
--- a/source/slang/slang-ir-link.h
+++ b/source/slang/slang-ir-link.h
@@ -12,6 +12,7 @@ namespace Slang
RefPtr<IRModule> module;
IRVarLayout* globalScopeVarLayout;
List<IRFunc*> entryPoints;
+ RefPtr<PostEmitMetadata> metadata;
};
diff --git a/source/slang/slang-ir-metadata.cpp b/source/slang/slang-ir-metadata.cpp
new file mode 100644
index 000000000..cc5922e93
--- /dev/null
+++ b/source/slang/slang-ir-metadata.cpp
@@ -0,0 +1,77 @@
+// slang-ir-metadata.cpp
+#include "slang-ir-metadata.h"
+
+#include "slang-ir.h"
+#include "slang-ir-insts.h"
+
+namespace Slang
+{
+
+// This file currently implements a pass that collects information about the shader parameters that
+// are referenced in the IR. It's named 'metadata' in order to support other potential code
+// analysis scenarios in the future.
+
+
+// Inserts a single resource binding (which takes `count` slots, where 0 means unbounded) into the list of resource ranges.
+static void _insertBinding(List<ShaderBindingRange>& ranges, LayoutResourceKind kind, UInt spaceIndex, UInt registerIndex, UInt count)
+{
+ // Construct a new range from the provided resource.
+ ShaderBindingRange newRange;
+ newRange.category = kind;
+ newRange.spaceIndex = spaceIndex;
+ newRange.registerIndex = registerIndex;
+ newRange.registerCount = count;
+
+ // See if the new range is adjacent to any of the existing ranges, merge with that.
+ for (auto& range : ranges)
+ {
+ if (range.adjacentTo(newRange))
+ {
+ range.mergeWith(newRange);
+ return;
+ }
+ }
+
+ // No adjacent ranges found - create a new one.
+ ranges.add(newRange);
+}
+
+// Collects the metadata from the provided IR module, saves it in outMetadata.
+void collectMetadata(const IRModule* irModule, PostEmitMetadata& outMetadata)
+{
+ // Scan the instructions looking for global resource declarations
+ for (const auto& inst : irModule->getGlobalInsts())
+ {
+ auto param = as<IRGlobalParam>(inst);
+ if (!param) continue;
+
+ auto layoutDecoration = param->findDecoration<IRLayoutDecoration>();
+ if (!layoutDecoration) continue;
+
+ auto varLayout = as<IRVarLayout>(layoutDecoration->getLayout());
+ if (!varLayout) continue;
+
+ for(auto sizeAttr : varLayout->getTypeLayout()->getSizeAttrs())
+ {
+ auto kind = sizeAttr->getResourceKind();
+
+ // Only track resource types that we can reliably track, such as textures.
+ // Do not track individual uniforms, for example.
+ if (!ShaderBindingRange::isUsageTracked(kind))
+ continue;
+
+ if (auto offsetAttr = varLayout->findOffsetAttr(kind))
+ {
+ // Get the binding information from this attribute and insert it into the list
+ auto spaceIndex = offsetAttr->getSpace();
+ auto registerIndex = offsetAttr->getOffset();
+ auto size = sizeAttr->getSize();
+ auto count = size.isFinite() ? size.getFiniteValue() : 0;
+ _insertBinding(outMetadata.usedBindings, kind, spaceIndex, registerIndex, count);
+ }
+ }
+ }
+}
+
+
+}
diff --git a/source/slang/slang-ir-metadata.h b/source/slang/slang-ir-metadata.h
new file mode 100644
index 000000000..b7fcd1e2b
--- /dev/null
+++ b/source/slang/slang-ir-metadata.h
@@ -0,0 +1,12 @@
+// slang-ir-metadata.h
+#pragma once
+
+namespace Slang
+{
+
+struct PostEmitMetadata;
+struct IRModule;
+
+void collectMetadata(const IRModule* irModule, PostEmitMetadata& outMetadata);
+
+}
diff --git a/source/slang/slang-reflection-api.cpp b/source/slang/slang-reflection-api.cpp
index 583e000a6..96b1f9004 100644
--- a/source/slang/slang-reflection-api.cpp
+++ b/source/slang/slang-reflection-api.cpp
@@ -2580,6 +2580,20 @@ SLANG_API unsigned spReflectionParameter_GetBindingSpace(SlangReflectionParamete
spReflectionVariableLayout_GetTypeLayout(varLayout)));
}
+SLANG_API SlangResult spIsParameterLocationUsed(
+ SlangCompileRequest* request,
+ SlangInt entryPointIndex,
+ SlangInt targetIndex,
+ SlangParameterCategory category,
+ SlangUInt spaceIndex,
+ SlangUInt registerIndex,
+ bool& outUsed)
+{
+ if (!request)
+ return SLANG_E_INVALID_ARG;
+
+ return request->isParameterLocationUsed(entryPointIndex, targetIndex, category, spaceIndex, registerIndex, outUsed);
+}
// Entry Point Reflection
diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp
index 7ce3594e5..7b22d04de 100644
--- a/source/slang/slang.cpp
+++ b/source/slang/slang.cpp
@@ -4147,6 +4147,11 @@ void EndToEndCompileRequest::setCompileFlags(SlangCompileFlags flags)
getFrontEndReq()->compileFlags = flags;
}
+SlangCompileFlags EndToEndCompileRequest::getCompileFlags()
+{
+ return getFrontEndReq()->compileFlags;
+}
+
void EndToEndCompileRequest::setDumpIntermediates(int enable)
{
shouldDumpIntermediates = (enable != 0);
@@ -4909,4 +4914,14 @@ SlangResult EndToEndCompileRequest::getEntryPoint(SlangInt entryPointIndex, slan
return SLANG_OK;
}
+SlangResult EndToEndCompileRequest::isParameterLocationUsed(Int entryPointIndex, Int targetIndex, SlangParameterCategory category, UInt spaceIndex, UInt registerIndex, bool& outUsed)
+{
+ CompileResult* compileResult = nullptr;
+ if (_getEntryPointResult(this, static_cast<int>(entryPointIndex), static_cast<int>(targetIndex), &compileResult) != SLANG_OK)
+ return SLANG_E_INVALID_ARG;
+
+ return compileResult->isParameterLocationUsed(category, spaceIndex, registerIndex, outUsed);
+}
+
+
} // namespace Slang
diff --git a/tests/cross-compile/cpp-resource-reflection.slang b/tests/cross-compile/cpp-resource-reflection.slang
index 3d6fa7638..98253259e 100644
--- a/tests/cross-compile/cpp-resource-reflection.slang
+++ b/tests/cross-compile/cpp-resource-reflection.slang
@@ -1,4 +1,4 @@
-//TEST:CPU_REFLECTION: -profile cs_5_0 -entry computeMain -target cpp
+//TEST:CPU_REFLECTION: -profile cs_5_0 -entry computeMain -target cpp -no-codegen
struct Thing
diff --git a/tests/cuda/cuda-reflection.slang b/tests/cuda/cuda-reflection.slang
index 95bf591c9..f7cef88c3 100644
--- a/tests/cuda/cuda-reflection.slang
+++ b/tests/cuda/cuda-reflection.slang
@@ -1,6 +1,6 @@
// cuda-reflection.slang
-//TEST:REFLECTION:-stage compute -entry main -target cuda
+//TEST:REFLECTION:-stage compute -entry main -target cuda -no-codegen
struct PadLadenStruct
{
diff --git a/tests/hlsl-intrinsic/sampler-feedback/sampler-feedback-basic.slang b/tests/hlsl-intrinsic/sampler-feedback/sampler-feedback-basic.slang
index 3b9497e5e..5f13a9ca7 100644
--- a/tests/hlsl-intrinsic/sampler-feedback/sampler-feedback-basic.slang
+++ b/tests/hlsl-intrinsic/sampler-feedback/sampler-feedback-basic.slang
@@ -1,4 +1,4 @@
-//TEST:REFLECTION: -entry main -stage fragment -profile sm_6_5 -target hlsl
+//TEST:REFLECTION: -entry main -stage fragment -profile sm_6_5 -target hlsl -no-codegen
//DISABLE_TEST:CROSS_COMPILE: -entry main -stage fragment -profile sm_6_5 -target dxil-assembly
FeedbackTexture2D<SAMPLER_FEEDBACK_MIN_MIP> feedbackMinMip;
diff --git a/tests/ir/string-literal-hash-reflection.slang b/tests/ir/string-literal-hash-reflection.slang
index 85d6ac3e4..a0a28876b 100644
--- a/tests/ir/string-literal-hash-reflection.slang
+++ b/tests/ir/string-literal-hash-reflection.slang
@@ -1,4 +1,4 @@
-//TEST:REFLECTION:-stage compute -entry computeMain -target hlsl
+//TEST:REFLECTION:-stage compute -entry computeMain -target hlsl -no-codegen
import string_literal_module;
diff --git a/tests/reflection/arrays.hlsl b/tests/reflection/arrays.hlsl
index d013bc498..20d18e91e 100644
--- a/tests/reflection/arrays.hlsl
+++ b/tests/reflection/arrays.hlsl
@@ -1,4 +1,4 @@
-//TEST:REFLECTION:-profile ps_4_0 -target hlsl
+//TEST:REFLECTION:-profile ps_4_0 -target hlsl -no-codegen
// Confirm that we can generate reflection info for arrays
//
diff --git a/tests/reflection/attribute.slang b/tests/reflection/attribute.slang
index 687148add..41179fcf5 100644
--- a/tests/reflection/attribute.slang
+++ b/tests/reflection/attribute.slang
@@ -2,7 +2,7 @@
// Tests reflection of user defined attributes.
-//TEST:REFLECTION:-stage compute -entry main -target hlsl
+//TEST:REFLECTION:-stage compute -entry main -target hlsl -no-codegen
[__AttributeUsage(_AttributeTargets.Struct)]
struct MyStructAttribute
diff --git a/tests/reflection/binding-gl.hlsl b/tests/reflection/binding-gl.hlsl
index cd2ab666a..04c65ca54 100644
--- a/tests/reflection/binding-gl.hlsl
+++ b/tests/reflection/binding-gl.hlsl
@@ -1,4 +1,4 @@
-//TEST:REFLECTION:-profile ps_4_0 -target spirv
+//TEST:REFLECTION:-profile ps_4_0 -target spirv -no-codegen
// Confirm that we can generate reflection info for arrays
//
diff --git a/tests/reflection/binding-push-constant-gl.hlsl b/tests/reflection/binding-push-constant-gl.hlsl
index f6bf13602..a3110f5cb 100644
--- a/tests/reflection/binding-push-constant-gl.hlsl
+++ b/tests/reflection/binding-push-constant-gl.hlsl
@@ -1,4 +1,4 @@
-//TEST:REFLECTION:-profile ps_4_0 -target spirv
+//TEST:REFLECTION:-profile ps_4_0 -target spirv -no-codegen
// Confirm that we can generate reflection info for arrays
//
diff --git a/tests/reflection/buffer-layout.slang b/tests/reflection/buffer-layout.slang
index 51b9680d1..b2cc3f724 100644
--- a/tests/reflection/buffer-layout.slang
+++ b/tests/reflection/buffer-layout.slang
@@ -4,8 +4,8 @@
// to confirm that our reflection logic correctly reports the offsets
// that the compute test sees in practice.
-//TEST:REFLECTION:-stage compute -entry main -target hlsl
-//TEST:REFLECTION:-stage compute -entry main -target spirv
+//TEST:REFLECTION:-stage compute -entry main -target hlsl -no-codegen
+//TEST:REFLECTION:-stage compute -entry main -target spirv -no-codegen
struct A
{
diff --git a/tests/reflection/cross-compile.slang b/tests/reflection/cross-compile.slang
index 600f3ed0f..30b080c64 100644
--- a/tests/reflection/cross-compile.slang
+++ b/tests/reflection/cross-compile.slang
@@ -1,4 +1,4 @@
-//TEST(smoke):REFLECTION:-profile glsl_fragment -target glsl
+//TEST(smoke):REFLECTION:-profile glsl_fragment -target glsl -no-codegen
// Confirm that when targetting GLSL via cross compilation,
// we use the Vulkan layout rules instead of HLSL ones
diff --git a/tests/reflection/default-space.slang b/tests/reflection/default-space.slang
index 666714b79..f279d71b2 100644
--- a/tests/reflection/default-space.slang
+++ b/tests/reflection/default-space.slang
@@ -1,4 +1,4 @@
-//TEST:REFLECTION:-profile sm_5_1 -stage fragment -target hlsl
+//TEST:REFLECTION:-profile sm_5_1 -stage fragment -target hlsl -no-codegen
// This test is to confirm that we do not allocate a "default"
// space/set for global shader parameters unless it is
diff --git a/tests/reflection/explicit-register-space.slang b/tests/reflection/explicit-register-space.slang
index d0bdc8178..79369037f 100644
--- a/tests/reflection/explicit-register-space.slang
+++ b/tests/reflection/explicit-register-space.slang
@@ -1,5 +1,5 @@
// explicit-register-space.slang
-//TEST:REFLECTION:-profile ps_5_1 -target hlsl
+//TEST:REFLECTION:-profile ps_5_1 -target hlsl -no-codegen
// Confirm that we handle explicit register spaces
// on global shader parameters.
diff --git a/tests/reflection/matrix-layout.slang b/tests/reflection/matrix-layout.slang
index a0c1cdff1..2f0fe6a41 100644
--- a/tests/reflection/matrix-layout.slang
+++ b/tests/reflection/matrix-layout.slang
@@ -1,5 +1,5 @@
-//TEST:REFLECTION:-profile ps_4_0 -target hlsl
-//TEST:REFLECTION:-profile ps_4_0 -target hlsl -matrix-layout-row-major
+//TEST:REFLECTION:-profile ps_4_0 -target hlsl -no-codegen
+//TEST:REFLECTION:-profile ps_4_0 -target hlsl -no-codegen -matrix-layout-row-major
// Test that we apply matrix layout rules correctly.
diff --git a/tests/reflection/mix-explicit-and-implicit-spaces.slang b/tests/reflection/mix-explicit-and-implicit-spaces.slang
index 52dd4321e..22e0163ee 100644
--- a/tests/reflection/mix-explicit-and-implicit-spaces.slang
+++ b/tests/reflection/mix-explicit-and-implicit-spaces.slang
@@ -1,5 +1,5 @@
// mix-explicit-and-implicit-spaces.slang
-//TEST:REFLECTION:-profile cs_5_1 -target hlsl
+//TEST:REFLECTION:-profile cs_5_1 -target hlsl -no-codegen
// Ensure that correct layout/reflection is computed
// when mixing implicit and explicit spaces for
diff --git a/tests/reflection/multi-file.hlsl b/tests/reflection/multi-file.hlsl
index fd9235ab5..6b42f807f 100644
--- a/tests/reflection/multi-file.hlsl
+++ b/tests/reflection/multi-file.hlsl
@@ -1,4 +1,4 @@
-//TEST:REFLECTION:-D__SLANG__ -entry mainVS -profile vs_4_0 -target hlsl tests/reflection/multi-file-extra.hlsl -entry mainFS -profile ps_4_0
+//TEST:REFLECTION:-D__SLANG__ -entry mainVS -profile vs_4_0 -target hlsl tests/reflection/multi-file-extra.hlsl -entry mainFS -profile ps_4_0 -no-codegen
// Here we are testing the case where multiple translation units are provided
// at once, so that we want combined reflection information for the resulting
diff --git a/tests/reflection/parameter-block-explicit-space.slang b/tests/reflection/parameter-block-explicit-space.slang
index b4d3eff9c..988584bec 100644
--- a/tests/reflection/parameter-block-explicit-space.slang
+++ b/tests/reflection/parameter-block-explicit-space.slang
@@ -1,6 +1,6 @@
// parameter-block-explicit-space.slang
-//TEST:REFLECTION:-D__SLANG__ -stage fragment -entry main -profile sm_5_1 -target hlsl
+//TEST:REFLECTION:-D__SLANG__ -stage fragment -entry main -profile sm_5_1 -target hlsl -no-codegen
//TEST:COMPARE_HLSL:-stage fragment -entry main -profile sm_5_1
#ifdef __SLANG__
diff --git a/tests/reflection/parameter-block.slang b/tests/reflection/parameter-block.slang
index 5c91ed339..67b49aadb 100644
--- a/tests/reflection/parameter-block.slang
+++ b/tests/reflection/parameter-block.slang
@@ -1,6 +1,6 @@
-//TEST:REFLECTION:-stage fragment -target glsl
-//TEST:REFLECTION:-stage fragment -target hlsl -profile sm_5_0
-//TEST:REFLECTION:-stage fragment -target hlsl -profile sm_5_1
+//TEST:REFLECTION:-stage fragment -target glsl -no-codegen
+//TEST:REFLECTION:-stage fragment -target hlsl -no-codegen -profile sm_5_0
+//TEST:REFLECTION:-stage fragment -target hlsl -no-codegen -profile sm_5_1
// Confirm that we do parameter binding correctly
// when we have both a parameter block *and* user-defined
diff --git a/tests/reflection/reflect-imported-code.hlsl b/tests/reflection/reflect-imported-code.hlsl
index c3562af35..9370639d2 100644
--- a/tests/reflection/reflect-imported-code.hlsl
+++ b/tests/reflection/reflect-imported-code.hlsl
@@ -1,4 +1,4 @@
-//TEST:REFLECTION:-profile ps_4_0 -target hlsl
+//TEST:REFLECTION:-profile ps_4_0 -target hlsl -no-codegen
// Confirm that shader parameters in imported modules get reflected properly.
diff --git a/tests/reflection/reflect-static.slang b/tests/reflection/reflect-static.slang
index f7a44cde8..cd4ebab80 100644
--- a/tests/reflection/reflect-static.slang
+++ b/tests/reflection/reflect-static.slang
@@ -1,4 +1,4 @@
-//TEST:REFLECTION:-profile cs_6_0 -target hlsl -entry computeMain
+//TEST:REFLECTION:-profile cs_6_0 -target hlsl -entry computeMain -no-codegen
struct Thing
{
diff --git a/tests/reflection/reflection0.hlsl b/tests/reflection/reflection0.hlsl
index 22232b59a..8865b7c35 100644
--- a/tests/reflection/reflection0.hlsl
+++ b/tests/reflection/reflection0.hlsl
@@ -1,4 +1,4 @@
-//TEST:REFLECTION:-profile ps_4_0 -target hlsl
+//TEST:REFLECTION:-profile ps_4_0 -target hlsl -no-codegen
// Confirm that basic reflection info can be output
diff --git a/tests/reflection/resource-in-cbuffer.hlsl b/tests/reflection/resource-in-cbuffer.hlsl
index b96f73113..7c016181c 100644
--- a/tests/reflection/resource-in-cbuffer.hlsl
+++ b/tests/reflection/resource-in-cbuffer.hlsl
@@ -1,4 +1,4 @@
-//TEST(smoke):REFLECTION:-profile ps_4_0 -target hlsl
+//TEST(smoke):REFLECTION:-profile ps_4_0 -target hlsl -no-codegen
// Confirm that we can generate reflection
// information for resources nested inside
diff --git a/tests/reflection/sample-index-input.hlsl b/tests/reflection/sample-index-input.hlsl
index edb0690d6..d4d797a26 100644
--- a/tests/reflection/sample-index-input.hlsl
+++ b/tests/reflection/sample-index-input.hlsl
@@ -1,4 +1,4 @@
-//TEST:REFLECTION:-profile ps_5_0 -target hlsl
+//TEST:REFLECTION:-profile ps_5_0 -target hlsl -no-codegen
// Confirm that we register a shader as sample-rate when
// it declares `SV_SampleIndex` as an input.
diff --git a/tests/reflection/sample-rate-input.hlsl b/tests/reflection/sample-rate-input.hlsl
index 0545afb02..f69149df8 100644
--- a/tests/reflection/sample-rate-input.hlsl
+++ b/tests/reflection/sample-rate-input.hlsl
@@ -1,4 +1,4 @@
-//TEST:REFLECTION:-profile ps_5_0 -target hlsl
+//TEST:REFLECTION:-profile ps_5_0 -target hlsl -no-codegen
// Confirm that we register a shader as sample-rate when
// it declares (not necessarly *uses*) a `sample` qualified input
diff --git a/tests/reflection/shared-modifier.hlsl b/tests/reflection/shared-modifier.hlsl
index 45a1dfac8..928bdb1c9 100644
--- a/tests/reflection/shared-modifier.hlsl
+++ b/tests/reflection/shared-modifier.hlsl
@@ -1,5 +1,5 @@
// shared-modifier.hlsl
-//TEST:REFLECTION:-profile ps_5_0 -target hlsl
+//TEST:REFLECTION:-profile ps_5_0 -target hlsl -no-codegen
// Confirm that we expose the `shared` modifier in reflection data.
diff --git a/tests/reflection/structured-buffer.slang b/tests/reflection/structured-buffer.slang
index 491d61486..b3d8b860b 100644
--- a/tests/reflection/structured-buffer.slang
+++ b/tests/reflection/structured-buffer.slang
@@ -1,4 +1,4 @@
-//TEST:REFLECTION:-profile ps_4_0 -target hlsl
+//TEST:REFLECTION:-profile ps_4_0 -target hlsl -no-codegen
// Confirm that we reflect the contents of structure-buffer types correctly.
diff --git a/tests/reflection/thread-group-size.hlsl b/tests/reflection/thread-group-size.hlsl
index 7e0400b46..13b3148d8 100644
--- a/tests/reflection/thread-group-size.hlsl
+++ b/tests/reflection/thread-group-size.hlsl
@@ -1,4 +1,4 @@
-//TEST:REFLECTION:-profile cs_5_0 -target hlsl
+//TEST:REFLECTION:-profile cs_5_0 -target hlsl -no-codegen
// Confirm that we provide reflection data for the `numthreads` attribute
diff --git a/tests/reflection/unbounded-arrays.hlsl b/tests/reflection/unbounded-arrays.hlsl
index 2c3b7a7bb..603bb6071 100644
--- a/tests/reflection/unbounded-arrays.hlsl
+++ b/tests/reflection/unbounded-arrays.hlsl
@@ -1,7 +1,7 @@
// unbounded-arrays.hlsl
//TEST:COMPARE_HLSL:-profile cs_5_1 -entry main
-//TEST:REFLECTION:-profile cs_5_1 -target hlsl -D__SLANG__
+//TEST:REFLECTION:-profile cs_5_1 -target hlsl -no-codegen -D__SLANG__
//
// This test is trying to make sure that we correctly compute
diff --git a/tests/reflection/used-parameters.slang b/tests/reflection/used-parameters.slang
new file mode 100644
index 000000000..efb605a14
--- /dev/null
+++ b/tests/reflection/used-parameters.slang
@@ -0,0 +1,52 @@
+// used-parameters.slang
+
+// Tests post-emit analysis of shader parameters to find out if they are used or not.
+
+//TEST:REFLECTION:-stage compute -entry main -target hlsl
+
+
+struct S
+{
+ uint2 Size;
+};
+
+ConstantBuffer<S> UsedCB;
+ConstantBuffer<S> UnusedCB;
+
+Texture2D UsedTexture;
+Texture2D UnusedTexture;
+
+Buffer<uint> UsedBuffer;
+Buffer<uint> UnusedBuffer;
+
+StructuredBuffer<uint> UsedStructuredBuffer;
+StructuredBuffer<uint> UnusedStructuredBuffer;
+
+RWTexture2D UsedRWTexture;
+RWTexture2D UnusedRWTexture;
+
+RWBuffer<uint> UsedRWBuffer;
+RWBuffer<uint> UnusedRWBuffer;
+
+RWStructuredBuffer<uint> UsedRWStructuredBuffer;
+RWStructuredBuffer<uint> UnusedRWStructuredBuffer;
+
+SamplerState UsedSampler;
+SamplerState UnusedSampler;
+
+uniform uint UsedUniform;
+uniform uint UnusedUniform;
+
+[numthreads(1, 1, 1)]
+void main(uint3 dispatchThreadID : SV_DispatchThreadID)
+{
+ float A = UsedTexture[dispatchThreadID.xy].x;
+ uint B = UsedBuffer[dispatchThreadID.x];
+ uint C = UsedStructuredBuffer[dispatchThreadID.y];
+ float D = UsedRWTexture[dispatchThreadID.xy].x;
+ uint E = UsedRWBuffer[dispatchThreadID.y];
+ float F = UsedTexture.SampleLevel(UsedSampler, float2(dispatchThreadID.xy) / float2(UsedCB.Size), 0).x;
+ uint G = UsedUniform;
+
+ UsedRWStructuredBuffer[dispatchThreadID.x + dispatchThreadID.y * UsedCB.Size.x] = uint(A) + B + C + uint(D) + E + uint(F) + G;
+} \ No newline at end of file
diff --git a/tests/reflection/used-parameters.slang.expected b/tests/reflection/used-parameters.slang.expected
new file mode 100644
index 000000000..2bbc5b41a
--- /dev/null
+++ b/tests/reflection/used-parameters.slang.expected
@@ -0,0 +1,350 @@
+result code = 0
+standard error = {
+}
+standard output = {
+{
+ "parameters": [
+ {
+ "name": "UsedCB",
+ "binding": {"kind": "constantBuffer", "index": 1},
+ "type": {
+ "kind": "constantBuffer",
+ "elementType": {
+ "kind": "struct",
+ "name": "S",
+ "fields": [
+ {
+ "name": "Size",
+ "type": {
+ "kind": "vector",
+ "elementCount": 2,
+ "elementType": {
+ "kind": "scalar",
+ "scalarType": "uint32"
+ }
+ },
+ "binding": {"kind": "uniform", "offset": 0, "size": 8}
+ }
+ ]
+ },
+ "containerVarLayout": {
+ "binding": {"kind": "constantBuffer", "index": 0}
+ },
+ "elementVarLayout": {
+ "type": {
+ "kind": "struct",
+ "name": "S",
+ "fields": [
+ {
+ "name": "Size",
+ "type": {
+ "kind": "vector",
+ "elementCount": 2,
+ "elementType": {
+ "kind": "scalar",
+ "scalarType": "uint32"
+ }
+ },
+ "binding": {"kind": "uniform", "offset": 0, "size": 8}
+ }
+ ]
+ },
+ "binding": {"kind": "uniform", "offset": 0, "size": 8}
+ }
+ }
+ },
+ {
+ "name": "UnusedCB",
+ "binding": {"kind": "constantBuffer", "index": 2},
+ "type": {
+ "kind": "constantBuffer",
+ "elementType": {
+ "kind": "struct",
+ "name": "S",
+ "fields": [
+ {
+ "name": "Size",
+ "type": {
+ "kind": "vector",
+ "elementCount": 2,
+ "elementType": {
+ "kind": "scalar",
+ "scalarType": "uint32"
+ }
+ },
+ "binding": {"kind": "uniform", "offset": 0, "size": 8}
+ }
+ ]
+ },
+ "containerVarLayout": {
+ "binding": {"kind": "constantBuffer", "index": 0}
+ },
+ "elementVarLayout": {
+ "type": {
+ "kind": "struct",
+ "name": "S",
+ "fields": [
+ {
+ "name": "Size",
+ "type": {
+ "kind": "vector",
+ "elementCount": 2,
+ "elementType": {
+ "kind": "scalar",
+ "scalarType": "uint32"
+ }
+ },
+ "binding": {"kind": "uniform", "offset": 0, "size": 8}
+ }
+ ]
+ },
+ "binding": {"kind": "uniform", "offset": 0, "size": 8}
+ }
+ }
+ },
+ {
+ "name": "UsedTexture",
+ "binding": {"kind": "shaderResource", "index": 0},
+ "type": {
+ "kind": "resource",
+ "baseShape": "texture2D"
+ }
+ },
+ {
+ "name": "UnusedTexture",
+ "binding": {"kind": "shaderResource", "index": 1},
+ "type": {
+ "kind": "resource",
+ "baseShape": "texture2D"
+ }
+ },
+ {
+ "name": "UsedBuffer",
+ "binding": {"kind": "shaderResource", "index": 2},
+ "type": {
+ "kind": "resource",
+ "baseShape": "textureBuffer"
+ }
+ },
+ {
+ "name": "UnusedBuffer",
+ "binding": {"kind": "shaderResource", "index": 3},
+ "type": {
+ "kind": "resource",
+ "baseShape": "textureBuffer"
+ }
+ },
+ {
+ "name": "UsedStructuredBuffer",
+ "binding": {"kind": "shaderResource", "index": 4},
+ "type": {
+ "kind": "resource",
+ "baseShape": "structuredBuffer",
+ "resultType": {
+ "kind": "scalar",
+ "scalarType": "uint32"
+ }
+ }
+ },
+ {
+ "name": "UnusedStructuredBuffer",
+ "binding": {"kind": "shaderResource", "index": 5},
+ "type": {
+ "kind": "resource",
+ "baseShape": "structuredBuffer",
+ "resultType": {
+ "kind": "scalar",
+ "scalarType": "uint32"
+ }
+ }
+ },
+ {
+ "name": "UsedRWTexture",
+ "binding": {"kind": "unorderedAccess", "index": 0},
+ "type": {
+ "kind": "resource",
+ "baseShape": "texture2D",
+ "access": "readWrite"
+ }
+ },
+ {
+ "name": "UnusedRWTexture",
+ "binding": {"kind": "unorderedAccess", "index": 1},
+ "type": {
+ "kind": "resource",
+ "baseShape": "texture2D",
+ "access": "readWrite"
+ }
+ },
+ {
+ "name": "UsedRWBuffer",
+ "binding": {"kind": "unorderedAccess", "index": 2},
+ "type": {
+ "kind": "resource",
+ "baseShape": "textureBuffer",
+ "access": "readWrite"
+ }
+ },
+ {
+ "name": "UnusedRWBuffer",
+ "binding": {"kind": "unorderedAccess", "index": 3},
+ "type": {
+ "kind": "resource",
+ "baseShape": "textureBuffer",
+ "access": "readWrite"
+ }
+ },
+ {
+ "name": "UsedRWStructuredBuffer",
+ "binding": {"kind": "unorderedAccess", "index": 4},
+ "type": {
+ "kind": "resource",
+ "baseShape": "structuredBuffer",
+ "access": "readWrite",
+ "resultType": {
+ "kind": "scalar",
+ "scalarType": "uint32"
+ }
+ }
+ },
+ {
+ "name": "UnusedRWStructuredBuffer",
+ "binding": {"kind": "unorderedAccess", "index": 5},
+ "type": {
+ "kind": "resource",
+ "baseShape": "structuredBuffer",
+ "access": "readWrite",
+ "resultType": {
+ "kind": "scalar",
+ "scalarType": "uint32"
+ }
+ }
+ },
+ {
+ "name": "UsedSampler",
+ "binding": {"kind": "samplerState", "index": 0},
+ "type": {
+ "kind": "samplerState"
+ }
+ },
+ {
+ "name": "UnusedSampler",
+ "binding": {"kind": "samplerState", "index": 1},
+ "type": {
+ "kind": "samplerState"
+ }
+ },
+ {
+ "name": "UsedUniform",
+ "binding": {"kind": "uniform", "offset": 0, "size": 4},
+ "type": {
+ "kind": "scalar",
+ "scalarType": "uint32"
+ }
+ },
+ {
+ "name": "UnusedUniform",
+ "binding": {"kind": "uniform", "offset": 4, "size": 4},
+ "type": {
+ "kind": "scalar",
+ "scalarType": "uint32"
+ }
+ }
+ ],
+ "entryPoints": [
+ {
+ "name": "main",
+ "stage:": "compute",
+ "parameters": [
+ {
+ "name": "dispatchThreadID",
+ "semanticName": "SV_DISPATCHTHREADID",
+ "type": {
+ "kind": "vector",
+ "elementCount": 3,
+ "elementType": {
+ "kind": "scalar",
+ "scalarType": "uint32"
+ }
+ }
+ }
+ ],
+ "threadGroupSize": [1, 1, 1],
+ "bindings": [
+ {
+ "name": "UsedCB",
+ "binding": {"kind": "constantBuffer", "index": 1, "used": 1}
+ },
+ {
+ "name": "UnusedCB",
+ "binding": {"kind": "constantBuffer", "index": 2, "used": 0}
+ },
+ {
+ "name": "UsedTexture",
+ "binding": {"kind": "shaderResource", "index": 0, "used": 1}
+ },
+ {
+ "name": "UnusedTexture",
+ "binding": {"kind": "shaderResource", "index": 1, "used": 0}
+ },
+ {
+ "name": "UsedBuffer",
+ "binding": {"kind": "shaderResource", "index": 2, "used": 1}
+ },
+ {
+ "name": "UnusedBuffer",
+ "binding": {"kind": "shaderResource", "index": 3, "used": 0}
+ },
+ {
+ "name": "UsedStructuredBuffer",
+ "binding": {"kind": "shaderResource", "index": 4, "used": 1}
+ },
+ {
+ "name": "UnusedStructuredBuffer",
+ "binding": {"kind": "shaderResource", "index": 5, "used": 0}
+ },
+ {
+ "name": "UsedRWTexture",
+ "binding": {"kind": "unorderedAccess", "index": 0, "used": 1}
+ },
+ {
+ "name": "UnusedRWTexture",
+ "binding": {"kind": "unorderedAccess", "index": 1, "used": 0}
+ },
+ {
+ "name": "UsedRWBuffer",
+ "binding": {"kind": "unorderedAccess", "index": 2, "used": 1}
+ },
+ {
+ "name": "UnusedRWBuffer",
+ "binding": {"kind": "unorderedAccess", "index": 3, "used": 0}
+ },
+ {
+ "name": "UsedRWStructuredBuffer",
+ "binding": {"kind": "unorderedAccess", "index": 4, "used": 1}
+ },
+ {
+ "name": "UnusedRWStructuredBuffer",
+ "binding": {"kind": "unorderedAccess", "index": 5, "used": 0}
+ },
+ {
+ "name": "UsedSampler",
+ "binding": {"kind": "samplerState", "index": 0, "used": 1}
+ },
+ {
+ "name": "UnusedSampler",
+ "binding": {"kind": "samplerState", "index": 1, "used": 0}
+ },
+ {
+ "name": "UsedUniform",
+ "binding": {"kind": "uniform", "offset": 0, "size": 4}
+ },
+ {
+ "name": "UnusedUniform",
+ "binding": {"kind": "uniform", "offset": 4, "size": 4}
+ }
+ ]
+ }
+ ]
+}
+}
diff --git a/tests/reflection/vertex-input-semantics.hlsl b/tests/reflection/vertex-input-semantics.hlsl
index 87a8431bc..356746bed 100644
--- a/tests/reflection/vertex-input-semantics.hlsl
+++ b/tests/reflection/vertex-input-semantics.hlsl
@@ -1,4 +1,4 @@
-//TEST:REFLECTION:-profile vs_4_0 -target hlsl
+//TEST:REFLECTION:-profile vs_4_0 -target hlsl -no-codegen
// Confirm that we can generate reflection info for
// vertex shader input parameters, including those
diff --git a/tools/slang-reflection-test/slang-reflection-test-main.cpp b/tools/slang-reflection-test/slang-reflection-test-main.cpp
index af6da5113..34fef404e 100644
--- a/tools/slang-reflection-test/slang-reflection-test-main.cpp
+++ b/tools/slang-reflection-test/slang-reflection-test-main.cpp
@@ -273,7 +273,9 @@ static void emitReflectionVarBindingInfoJSON(
static void emitReflectionVarBindingInfoJSON(
PrettyWriter& writer,
- slang::VariableLayoutReflection* var)
+ slang::VariableLayoutReflection* var,
+ SlangCompileRequest* request = nullptr,
+ int entryPointIndex = -1)
{
auto stage = var->getStage();
if (stage != SLANG_STAGE_NONE)
@@ -321,15 +323,28 @@ static void emitReflectionVarBindingInfoJSON(
auto space = var->getBindingSpace(category);
auto count = typeLayout->getSize(category);
+ // Query the paramater usage for the specified entry point.
+ // Note: both `request` and `entryPointIndex` may be invalid here, but that should just make the function return a failure.
+ bool used = false;
+ bool usedAvailable = spIsParameterLocationUsed(request, entryPointIndex, 0, category, space, index, used) == SLANG_OK;
+
if (cc != 0) write(writer, ",\n");
write(writer,"{");
+
emitReflectionVarBindingInfoJSON(
writer,
category,
index,
count,
space);
+
+ if (usedAvailable)
+ {
+ write(writer, ", \"used\": ");
+ write(writer, used);
+ }
+
write(writer,"}");
}
@@ -1030,6 +1045,27 @@ static void emitReflectionParamJSON(
write(writer, "\n}");
}
+
+static void emitEntryPointParamJSON(
+ PrettyWriter& writer,
+ slang::VariableLayoutReflection* param,
+ SlangCompileRequest* request,
+ int entryPointIndex)
+{
+ write(writer, "{\n");
+ indent(writer);
+
+ if( auto name = param->getName() )
+ {
+ emitReflectionNameInfoJSON(writer, name);
+ }
+
+ emitReflectionVarBindingInfoJSON(writer, param, request, entryPointIndex);
+
+ dedent(writer);
+ write(writer, "\n}");
+}
+
template<typename T>
struct Range
{
@@ -1110,8 +1146,12 @@ static void emitReflectionTypeParamJSON(
static void emitReflectionEntryPointJSON(
PrettyWriter& writer,
- slang::EntryPointReflection* entryPoint)
+ SlangCompileRequest* request,
+ slang::ShaderReflection* programReflection,
+ int entryPointIndex)
{
+ slang::EntryPointReflection* entryPoint = programReflection->getEntryPointByIndex(entryPointIndex);
+
write(writer, "{\n");
indent(writer);
@@ -1170,12 +1210,32 @@ static void emitReflectionEntryPointJSON(
write(writer, "]");
}
+ // If code generation has been performed, print out the parameter usage by this entry point.
+ if ((request->getCompileFlags() & SLANG_COMPILE_FLAG_NO_CODEGEN) == 0)
+ {
+ write(writer, ",\n\"bindings\": [\n");
+ indent(writer);
+
+ auto parameterCount = programReflection->getParameterCount();
+ for( auto pp : range(parameterCount) )
+ {
+ if(pp != 0) write(writer, ",\n");
+
+ auto parameter = programReflection->getParameterByIndex(pp);
+ emitEntryPointParamJSON(writer, parameter, request, entryPointIndex);
+ }
+
+ dedent(writer);
+ write(writer, "\n]");
+ }
+
dedent(writer);
write(writer, "\n}");
}
static void emitReflectionJSON(
PrettyWriter& writer,
+ SlangCompileRequest* request,
slang::ShaderReflection* programReflection)
{
write(writer, "{\n");
@@ -1200,13 +1260,12 @@ static void emitReflectionJSON(
{
write(writer, ",\n\"entryPoints\": [\n");
indent(writer);
-
+
for (auto ee : range(entryPointCount))
{
if (ee != 0) write(writer, ",\n");
- auto entryPoint = programReflection->getEntryPointByIndex(ee);
- emitReflectionEntryPointJSON(writer, entryPoint);
+ emitReflectionEntryPointJSON(writer, request, programReflection, (int)ee);
}
dedent(writer);
@@ -1264,13 +1323,14 @@ static void emitReflectionJSON(
}
void emitReflectionJSON(
+ SlangCompileRequest* request,
SlangReflection* reflection)
{
auto programReflection = (slang::ShaderReflection*) reflection;
PrettyWriter writer;
- emitReflectionJSON(writer, programReflection);
+ emitReflectionJSON(writer, request, programReflection);
}
static SlangResult maybeDumpDiagnostic(SlangResult res, SlangCompileRequest* request)
@@ -1285,15 +1345,6 @@ static SlangResult maybeDumpDiagnostic(SlangResult res, SlangCompileRequest* req
SlangResult performCompilationAndReflection(SlangCompileRequest* request, int argc, const char*const* argv)
{
- // We don't actually need codegen to get reflection.
- //
- // Ideally perhaps this would use a call to
- // request->setCompileFlags(flags);
- // But that relies on knowing what flags are set, and there isn't a way to get that, so do it arg way
-
- const char* noCodeGenArgs[] = { "-no-codegen" };
- SLANG_RETURN_ON_FAIL(maybeDumpDiagnostic(spProcessCommandLineArguments(request, noCodeGenArgs, SLANG_COUNT_OF(noCodeGenArgs)), request));
-
SLANG_RETURN_ON_FAIL(maybeDumpDiagnostic(spProcessCommandLineArguments(request, &argv[1], argc - 1), request));
SLANG_RETURN_ON_FAIL(maybeDumpDiagnostic(spCompile(request), request));
@@ -1301,7 +1352,7 @@ SlangResult performCompilationAndReflection(SlangCompileRequest* request, int ar
// we have.
SlangReflection* reflection = spGetReflection(request);
- emitReflectionJSON(reflection);
+ emitReflectionJSON(request, reflection);
return SLANG_OK;
}