summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Foley <tfoleyNV@users.noreply.github.com>2017-12-15 14:26:58 -0800
committerGitHub <noreply@github.com>2017-12-15 14:26:58 -0800
commit46b68ed41daecfaf1761e299cf040156e0f65ac0 (patch)
tree678ac2ae7fcbe3d82dd56e1a0d68c5f235532d58
parent81c0cd872bcb94f1f05abc3b234d8918d237d77c (diff)
Add sample-rate-input detection for HLSL. (#312)
* Add sample-rate-input detection for HLSL. In the HLSL case, it is possible to do this detection entirely based on declared signatures (it doesn't have a dependency on code generation like the GLSL case does). I've added test cases for the two main ways that a shader can become sample rate: 1. Qualify a fragment input with `sample` 2. Accept an input with the `SV_SampleIndex` semantic In each case I nested the input inside a `struct` to try to match common HLSL idiom, and to make sure that we handle the nested case. This code is *not* robust against shaders that declare such an input and then never use it, but that is to be expected given the goals for Slang. * Fixup: add missing test output files
-rw-r--r--source/slang/parameter-binding.cpp64
-rw-r--r--tests/reflection/sample-index-input.hlsl15
-rw-r--r--tests/reflection/sample-index-input.hlsl.expected52
-rw-r--r--tests/reflection/sample-rate-input.hlsl15
-rw-r--r--tests/reflection/sample-rate-input.hlsl.expected58
5 files changed, 190 insertions, 14 deletions
diff --git a/source/slang/parameter-binding.cpp b/source/slang/parameter-binding.cpp
index 4eb1cf6ee..4ec4f6fd5 100644
--- a/source/slang/parameter-binding.cpp
+++ b/source/slang/parameter-binding.cpp
@@ -263,6 +263,9 @@ struct ParameterBindingContext
// What stage (if any) are we compiling for?
Stage stage;
+ // The entry point that is being processed right now.
+ EntryPointLayout* entryPointLayout = nullptr;
+
// The source language we are trying to use
SourceLanguage sourceLanguage;
@@ -647,6 +650,7 @@ struct EntryPointParameterState
EntryPointParameterDirectionMask directionMask;
int semanticSlotCount;
Stage stage = Stage::Unknown;
+ bool isSampleRate = false;
};
@@ -1276,6 +1280,14 @@ static RefPtr<TypeLayout> processSimpleEntryPointParameter(
}
}
+ if (state.directionMask & kEntryPointParameterDirection_Input)
+ {
+ if (sn == "sv_sampleindex")
+ {
+ state.isSampleRate = true;
+ }
+ }
+
// Remember the system-value semantic so that we can query it later
if (varLayout)
{
@@ -1308,33 +1320,53 @@ static RefPtr<TypeLayout> processSimpleEntryPointParameter(
}
}
+ if (state.isSampleRate
+ && (state.directionMask & kEntryPointParameterDirection_Input)
+ && (context->stage == Stage::Fragment))
+ {
+ if (auto entryPointLayout = context->entryPointLayout)
+ {
+ entryPointLayout->flags |= EntryPointLayout::Flag::usesAnySampleRateInput;
+ }
+ }
+
*state.ioSemanticIndex += state.semanticSlotCount;
typeLayout->type = type;
return typeLayout;
}
-static RefPtr<TypeLayout> processEntryPointParameterWithPossibleSemantic(
+static RefPtr<TypeLayout> processEntryPointParameterDecl(
ParameterBindingContext* context,
- Decl* declForSemantic,
- RefPtr<Type> type,
- EntryPointParameterState const& state,
+ Decl* decl,
+ RefPtr<Type> type,
+ EntryPointParameterState const& inState,
RefPtr<VarLayout> varLayout)
{
+ SimpleSemanticInfo semanticInfo;
+ int semanticIndex = 0;
+
+ EntryPointParameterState state = inState;
+
// If there is no explicit semantic already in effect, *and* we find an explicit
// semantic on the associated declaration, then we'll use it.
if( !state.optSemanticName )
{
- if( auto semantic = declForSemantic->FindModifier<HLSLSimpleSemantic>() )
+ if( auto semantic = decl->FindModifier<HLSLSimpleSemantic>() )
{
- auto semanticInfo = decomposeSimpleSemantic(semantic);
- int semanticIndex = semanticInfo.index;
+ semanticInfo = decomposeSimpleSemantic(semantic);
+ semanticIndex = semanticInfo.index;
- EntryPointParameterState subState = state;
- subState.optSemanticName = &semanticInfo.name;
- subState.ioSemanticIndex = &semanticIndex;
+ state.optSemanticName = &semanticInfo.name;
+ state.ioSemanticIndex = &semanticIndex;
+ }
+ }
- return processEntryPointParameter(context, type, subState, varLayout);
+ if (decl)
+ {
+ if (decl->FindModifier<HLSLSampleModifier>())
+ {
+ state.isSampleRate = true;
}
}
@@ -1441,7 +1473,7 @@ static RefPtr<TypeLayout> processEntryPointParameter(
RefPtr<VarLayout> fieldVarLayout = new VarLayout();
fieldVarLayout->varDecl = field;
- auto fieldTypeLayout = processEntryPointParameterWithPossibleSemantic(
+ auto fieldTypeLayout = processEntryPointParameterDecl(
context,
field.getDecl(),
GetType(field),
@@ -1512,6 +1544,8 @@ static void collectEntryPointParameters(
entryPointLayout->profile = entryPoint->profile;
entryPointLayout->entryPoint = entryPointFuncDecl;
+ context->entryPointLayout = entryPointLayout;
+
context->shared->programLayout->entryPoints.Add(entryPointLayout);
@@ -1559,7 +1593,7 @@ static void collectEntryPointParameters(
RefPtr<VarLayout> paramVarLayout = new VarLayout();
paramVarLayout->varDecl = makeDeclRef(paramDecl.Ptr());
- auto paramTypeLayout = processEntryPointParameterWithPossibleSemantic(
+ auto paramTypeLayout = processEntryPointParameterDecl(
context,
paramDecl.Ptr(),
paramDecl->type.type->Substitute(typeSubst).As<Type>(),
@@ -1591,7 +1625,7 @@ static void collectEntryPointParameters(
RefPtr<VarLayout> resultLayout = new VarLayout();
- auto resultTypeLayout = processEntryPointParameterWithPossibleSemantic(
+ auto resultTypeLayout = processEntryPointParameterDecl(
context,
entryPointFuncDecl,
resultType->Substitute(typeSubst).As<Type>(),
@@ -1689,6 +1723,7 @@ static void collectParameters(
context->stage = entryPoint->profile.GetStage();
collectEntryPointParameters(context, entryPoint.Ptr(), nullptr);
}
+ context->entryPointLayout = nullptr;
}
// Now collect parameters from loaded modules
@@ -2065,6 +2100,7 @@ RefPtr<ProgramLayout> specializeProgramLayout(
{
collectEntryPointParameters(&context, entryPoint, typeSubst);
}
+ context.entryPointLayout = nullptr;
}
auto constantBufferRules = context.getRulesFamily()->getConstantBufferRules();
diff --git a/tests/reflection/sample-index-input.hlsl b/tests/reflection/sample-index-input.hlsl
new file mode 100644
index 000000000..edb0690d6
--- /dev/null
+++ b/tests/reflection/sample-index-input.hlsl
@@ -0,0 +1,15 @@
+//TEST:REFLECTION:-profile ps_5_0 -target hlsl
+
+// Confirm that we register a shader as sample-rate when
+// it declares `SV_SampleIndex` as an input.
+
+struct PSInput
+{
+ float4 color : COLOR;
+ uint sampleIndex : SV_SampleIndex;
+};
+
+float4 main(PSInput input) : SV_Target
+{
+ return input.color;
+} \ No newline at end of file
diff --git a/tests/reflection/sample-index-input.hlsl.expected b/tests/reflection/sample-index-input.hlsl.expected
new file mode 100644
index 000000000..5bf5f297e
--- /dev/null
+++ b/tests/reflection/sample-index-input.hlsl.expected
@@ -0,0 +1,52 @@
+result code = 0
+standard error = {
+}
+standard output = {
+{
+ "parameters": [
+
+ ],
+ "entryPoints": [
+ {
+ "name": "main",
+ "stage:": "fragment",
+ "parameters": [
+ {
+ "name": "input",
+ "stage": "fragment",
+ "binding": {"kind": "varyingInput", "index": 0},
+ "type": {
+ "kind": "struct",
+ "name": "PSInput",
+ "fields": [
+ {
+ "name": "color",
+ "type": {
+ "kind": "vector",
+ "elementCount": 4,
+ "elementType": {
+ "kind": "scalar",
+ "scalarType": "float32"
+ }
+ },
+ "stage": "fragment",
+ "binding": {"kind": "varyingInput", "index": 0},
+ "semanticName": "COLOR"
+ },
+ {
+ "name": "sampleIndex",
+ "type": {
+ "kind": "scalar",
+ "scalarType": "uint32"
+ },
+ "semanticName": "SV_SAMPLEINDEX"
+ }
+ ]
+ }
+ }
+ ],
+ "usesAnySampleRateInput": true
+ }
+ ]
+}
+}
diff --git a/tests/reflection/sample-rate-input.hlsl b/tests/reflection/sample-rate-input.hlsl
new file mode 100644
index 000000000..0545afb02
--- /dev/null
+++ b/tests/reflection/sample-rate-input.hlsl
@@ -0,0 +1,15 @@
+//TEST:REFLECTION:-profile ps_5_0 -target hlsl
+
+// Confirm that we register a shader as sample-rate when
+// it declares (not necessarly *uses*) a `sample` qualified input
+
+struct PSInput
+{
+ float4 extra : EXTRA;
+ sample float4 color : COLOR;
+};
+
+float4 main(PSInput input) : SV_Target
+{
+ return input.extra + input.color;
+} \ No newline at end of file
diff --git a/tests/reflection/sample-rate-input.hlsl.expected b/tests/reflection/sample-rate-input.hlsl.expected
new file mode 100644
index 000000000..0c86ebecb
--- /dev/null
+++ b/tests/reflection/sample-rate-input.hlsl.expected
@@ -0,0 +1,58 @@
+result code = 0
+standard error = {
+}
+standard output = {
+{
+ "parameters": [
+
+ ],
+ "entryPoints": [
+ {
+ "name": "main",
+ "stage:": "fragment",
+ "parameters": [
+ {
+ "name": "input",
+ "stage": "fragment",
+ "binding": {"kind": "varyingInput", "index": 0, "count": 2},
+ "type": {
+ "kind": "struct",
+ "name": "PSInput",
+ "fields": [
+ {
+ "name": "extra",
+ "type": {
+ "kind": "vector",
+ "elementCount": 4,
+ "elementType": {
+ "kind": "scalar",
+ "scalarType": "float32"
+ }
+ },
+ "stage": "fragment",
+ "binding": {"kind": "varyingInput", "index": 0},
+ "semanticName": "EXTRA"
+ },
+ {
+ "name": "color",
+ "type": {
+ "kind": "vector",
+ "elementCount": 4,
+ "elementType": {
+ "kind": "scalar",
+ "scalarType": "float32"
+ }
+ },
+ "stage": "fragment",
+ "binding": {"kind": "varyingInput", "index": 1},
+ "semanticName": "COLOR"
+ }
+ ]
+ }
+ }
+ ],
+ "usesAnySampleRateInput": true
+ }
+ ]
+}
+}