HLSL: Manually configure descriptor set and binding number for resources
diff --git a/StandAlone/StandAlone.cpp b/StandAlone/StandAlone.cpp
index 3faadec..b21f20d 100644
--- a/StandAlone/StandAlone.cpp
+++ b/StandAlone/StandAlone.cpp
@@ -168,6 +168,7 @@
std::array<unsigned int, EShLangCount> baseUboBinding;
std::array<unsigned int, EShLangCount> baseSsboBinding;
std::array<unsigned int, EShLangCount> baseUavBinding;
+std::array<std::vector<std::string>, EShLangCount> baseResourceSetBinding;
//
// Create the default name for saving a binary if -o is not provided.
@@ -245,6 +246,45 @@
}
}
+void ProcessResourceSetBindingBase(int& argc, char**& argv, std::array<std::vector<std::string>, EShLangCount>& base)
+{
+ if (argc < 2)
+ usage();
+
+ if (!isdigit(argv[1][0])) {
+ if (argc < 5) // this form needs one more argument
+ usage();
+
+ // Parse form: --argname stage base
+ const EShLanguage lang = FindLanguage(argv[1], false);
+
+ base[lang].push_back(argv[2]);
+ base[lang].push_back(argv[3]);
+ base[lang].push_back(argv[4]);
+ argc-= 4;
+ argv+= 4;
+ while(argv[1] != NULL) {
+ if(argv[1][0] != '-') {
+ base[lang].push_back(argv[1]);
+ base[lang].push_back(argv[2]);
+ base[lang].push_back(argv[3]);
+ argc-= 3;
+ argv+= 3;
+ }
+ else {
+ break;
+ }
+ }
+ } else {
+ // Parse form: --argname base
+ for (int lang=0; lang<EShLangCount; ++lang)
+ base[lang].push_back(argv[1]);
+
+ argc--;
+ argv++;
+ }
+}
+
//
// Do all command-line argument parsing. This includes building up the work-items
// to be processed later, and saving all the command-line options.
@@ -297,6 +337,10 @@
lowerword == "shift-ssbo-binding" ||
lowerword == "sbb") {
ProcessBindingBase(argc, argv, baseSsboBinding);
+ } else if (lowerword == "resource-set-bindings" || // synonyms
+ lowerword == "resource-set-binding" ||
+ lowerword == "rsb") {
+ ProcessResourceSetBindingBase(argc, argv, baseResourceSetBinding);
} else if (lowerword == "shift-uav-bindings" || // synonyms
lowerword == "shift-uav-binding" ||
lowerword == "suavb") {
@@ -594,6 +638,7 @@
shader->setShiftUavBinding(baseUavBinding[compUnit.stage]);
shader->setFlattenUniformArrays((Options & EOptionFlattenUniformArrays) != 0);
shader->setNoStorageFormat((Options & EOptionNoStorageFormat) != 0);
+ shader->setResourceSetBinding(baseResourceSetBinding[compUnit.stage]);
if (Options & EOptionHlslIoMapping)
shader->setHlslIoMapping(true);
@@ -1006,6 +1051,9 @@
" --shift-ssbo-binding [stage] num set base binding number for SSBOs\n"
" --sbb [stage] num synonym for --shift-ssbo-binding\n"
"\n"
+ " --resource-set-binding [stage] num set descriptor set and binding number for resources\n"
+ " --rsb [stage] type set binding synonym for --resource-set-binding\n"
+ "\n"
" --shift-uav-binding [stage] num set base binding number for UAVs\n"
" --suavb [stage] num synonym for --shift-uav-binding\n"
"\n"
diff --git a/Test/baseResults/hlsl.multiDescriptorSet.frag.out b/Test/baseResults/hlsl.multiDescriptorSet.frag.out
new file mode 100644
index 0000000..c6fb83f
--- /dev/null
+++ b/Test/baseResults/hlsl.multiDescriptorSet.frag.out
@@ -0,0 +1,173 @@
+hlsl.multiDescriptorSet.frag
+// Module Version 10000
+// Generated by (magic number): 80001
+// Id's are bound by 95
+
+ Capability Shader
+ 1: ExtInstImport "GLSL.std.450"
+ MemoryModel Logical GLSL450
+ EntryPoint Fragment 4 "main" 78 83 89
+ ExecutionMode 4 OriginUpperLeft
+ Source HLSL 500
+ Name 4 "main"
+ Name 9 "PS_INPUT"
+ MemberName 9(PS_INPUT) 0 "Pos"
+ MemberName 9(PS_INPUT) 1 "Tex"
+ Name 13 "@main(struct-PS_INPUT-vf4-vf21;"
+ Name 12 "input"
+ Name 15 "output"
+ Name 23 "cbChangesEveryFrame"
+ MemberName 23(cbChangesEveryFrame) 0 "World"
+ MemberName 23(cbChangesEveryFrame) 1 "vMeshColor"
+ Name 25 ""
+ Name 34 "cbNeverChanges"
+ MemberName 34(cbNeverChanges) 0 "View"
+ Name 36 ""
+ Name 43 "cbChangeOnResize"
+ MemberName 43(cbChangeOnResize) 0 "Projection"
+ Name 45 ""
+ Name 59 "txDiffuseA"
+ Name 63 "samLinearA"
+ Name 76 "input"
+ Name 78 "input_Pos"
+ Name 81 "PS_INPUT"
+ MemberName 81(PS_INPUT) 0 "Tex"
+ Name 83 "input"
+ Name 89 "@entryPointOutput"
+ Name 90 "param"
+ Name 93 "txDiffuseB"
+ Name 94 "samLinearB"
+ MemberDecorate 23(cbChangesEveryFrame) 0 RowMajor
+ MemberDecorate 23(cbChangesEveryFrame) 0 Offset 0
+ MemberDecorate 23(cbChangesEveryFrame) 0 MatrixStride 16
+ MemberDecorate 23(cbChangesEveryFrame) 1 Offset 64
+ Decorate 23(cbChangesEveryFrame) Block
+ Decorate 25 DescriptorSet 2
+ Decorate 25 Binding 2
+ MemberDecorate 34(cbNeverChanges) 0 RowMajor
+ MemberDecorate 34(cbNeverChanges) 0 Offset 0
+ MemberDecorate 34(cbNeverChanges) 0 MatrixStride 16
+ Decorate 34(cbNeverChanges) Block
+ Decorate 36 DescriptorSet 2
+ Decorate 36 Binding 0
+ MemberDecorate 43(cbChangeOnResize) 0 RowMajor
+ MemberDecorate 43(cbChangeOnResize) 0 Offset 0
+ MemberDecorate 43(cbChangeOnResize) 0 MatrixStride 16
+ Decorate 43(cbChangeOnResize) Block
+ Decorate 45 DescriptorSet 2
+ Decorate 45 Binding 1
+ Decorate 59(txDiffuseA) DescriptorSet 0
+ Decorate 59(txDiffuseA) Binding 0
+ Decorate 63(samLinearA) DescriptorSet 0
+ Decorate 63(samLinearA) Binding 1
+ Decorate 78(input_Pos) BuiltIn FragCoord
+ Decorate 83(input) Location 0
+ Decorate 89(@entryPointOutput) Location 0
+ Decorate 93(txDiffuseB) DescriptorSet 1
+ Decorate 93(txDiffuseB) Binding 0
+ Decorate 94(samLinearB) DescriptorSet 1
+ Decorate 94(samLinearB) Binding 1
+ 2: TypeVoid
+ 3: TypeFunction 2
+ 6: TypeFloat 32
+ 7: TypeVector 6(float) 4
+ 8: TypeVector 6(float) 2
+ 9(PS_INPUT): TypeStruct 7(fvec4) 8(fvec2)
+ 10: TypePointer Function 9(PS_INPUT)
+ 11: TypeFunction 7(fvec4) 10(ptr)
+ 16: 6(float) Constant 0
+ 17: 7(fvec4) ConstantComposite 16 16 16 16
+ 18: 8(fvec2) ConstantComposite 16 16
+ 19: 9(PS_INPUT) ConstantComposite 17 18
+ 20: TypeInt 32 1
+ 21: 20(int) Constant 0
+ 22: TypeMatrix 7(fvec4) 4
+23(cbChangesEveryFrame): TypeStruct 22 7(fvec4)
+ 24: TypePointer Uniform 23(cbChangesEveryFrame)
+ 25: 24(ptr) Variable Uniform
+ 26: TypePointer Uniform 22
+ 29: TypePointer Function 7(fvec4)
+34(cbNeverChanges): TypeStruct 22
+ 35: TypePointer Uniform 34(cbNeverChanges)
+ 36: 35(ptr) Variable Uniform
+43(cbChangeOnResize): TypeStruct 22
+ 44: TypePointer Uniform 43(cbChangeOnResize)
+ 45: 44(ptr) Variable Uniform
+ 52: 20(int) Constant 1
+ 53: TypePointer Function 8(fvec2)
+ 57: TypeImage 6(float) 2D sampled format:Unknown
+ 58: TypePointer UniformConstant 57
+ 59(txDiffuseA): 58(ptr) Variable UniformConstant
+ 61: TypeSampler
+ 62: TypePointer UniformConstant 61
+ 63(samLinearA): 62(ptr) Variable UniformConstant
+ 65: TypeSampledImage 57
+ 70: TypePointer Uniform 7(fvec4)
+ 77: TypePointer Input 7(fvec4)
+ 78(input_Pos): 77(ptr) Variable Input
+ 81(PS_INPUT): TypeStruct 8(fvec2)
+ 82: TypePointer Input 81(PS_INPUT)
+ 83(input): 82(ptr) Variable Input
+ 84: TypePointer Input 8(fvec2)
+ 88: TypePointer Output 7(fvec4)
+89(@entryPointOutput): 88(ptr) Variable Output
+ 93(txDiffuseB): 58(ptr) Variable UniformConstant
+ 94(samLinearB): 62(ptr) Variable UniformConstant
+ 4(main): 2 Function None 3
+ 5: Label
+ 76(input): 10(ptr) Variable Function
+ 90(param): 10(ptr) Variable Function
+ 79: 7(fvec4) Load 78(input_Pos)
+ 80: 29(ptr) AccessChain 76(input) 21
+ Store 80 79
+ 85: 84(ptr) AccessChain 83(input) 21
+ 86: 8(fvec2) Load 85
+ 87: 53(ptr) AccessChain 76(input) 52
+ Store 87 86
+ 91: 9(PS_INPUT) Load 76(input)
+ Store 90(param) 91
+ 92: 7(fvec4) FunctionCall 13(@main(struct-PS_INPUT-vf4-vf21;) 90(param)
+ Store 89(@entryPointOutput) 92
+ Return
+ FunctionEnd
+13(@main(struct-PS_INPUT-vf4-vf21;): 7(fvec4) Function None 11
+ 12(input): 10(ptr) FunctionParameter
+ 14: Label
+ 15(output): 10(ptr) Variable Function
+ Store 15(output) 19
+ 27: 26(ptr) AccessChain 25 21
+ 28: 22 Load 27
+ 30: 29(ptr) AccessChain 12(input) 21
+ 31: 7(fvec4) Load 30
+ 32: 7(fvec4) MatrixTimesVector 28 31
+ 33: 29(ptr) AccessChain 15(output) 21
+ Store 33 32
+ 37: 26(ptr) AccessChain 36 21
+ 38: 22 Load 37
+ 39: 29(ptr) AccessChain 15(output) 21
+ 40: 7(fvec4) Load 39
+ 41: 7(fvec4) MatrixTimesVector 38 40
+ 42: 29(ptr) AccessChain 15(output) 21
+ Store 42 41
+ 46: 26(ptr) AccessChain 45 21
+ 47: 22 Load 46
+ 48: 29(ptr) AccessChain 15(output) 21
+ 49: 7(fvec4) Load 48
+ 50: 7(fvec4) MatrixTimesVector 47 49
+ 51: 29(ptr) AccessChain 15(output) 21
+ Store 51 50
+ 54: 53(ptr) AccessChain 12(input) 52
+ 55: 8(fvec2) Load 54
+ 56: 53(ptr) AccessChain 15(output) 52
+ Store 56 55
+ 60: 57 Load 59(txDiffuseA)
+ 64: 61 Load 63(samLinearA)
+ 66: 65 SampledImage 60 64
+ 67: 53(ptr) AccessChain 15(output) 52
+ 68: 8(fvec2) Load 67
+ 69: 7(fvec4) ImageSampleImplicitLod 66 68
+ 71: 70(ptr) AccessChain 25 52
+ 72: 7(fvec4) Load 71
+ 73: 7(fvec4) FMul 69 72
+ ReturnValue 73
+ FunctionEnd
diff --git a/Test/hlsl.multiDescriptorSet.frag b/Test/hlsl.multiDescriptorSet.frag
new file mode 100644
index 0000000..6c4be21
--- /dev/null
+++ b/Test/hlsl.multiDescriptorSet.frag
@@ -0,0 +1,45 @@
+Texture2D txDiffuseA : register( t0 );
+Texture2D txDiffuseB : register( t1 );
+
+SamplerState samLinearA : register( s0 );
+SamplerState samLinearB : register( s1 );
+
+cbuffer cbNeverChanges : register( b0 )
+{
+ matrix View;
+};
+
+cbuffer cbChangeOnResize : register( b1 )
+{
+ matrix Projection;
+};
+
+cbuffer cbChangesEveryFrame : register( b2 )
+{
+ matrix World;
+ float4 vMeshColor;
+};
+
+
+struct VS_INPUT
+{
+ float4 Pos : POSITION;
+ float2 Tex : TEXCOORD0;
+};
+
+struct PS_INPUT
+{
+ float4 Pos : SV_POSITION;
+ float2 Tex : TEXCOORD0;
+};
+
+
+float4 main( PS_INPUT input) : SV_Target
+{
+ PS_INPUT output = (PS_INPUT)0;
+ output.Pos = mul( input.Pos, World );
+ output.Pos = mul( output.Pos, View );
+ output.Pos = mul( output.Pos, Projection );
+ output.Tex = input.Tex;
+ return txDiffuseA.Sample( samLinearA, output.Tex ) * vMeshColor;
+}
diff --git a/Test/runtests b/Test/runtests
index 176e73f..4edb8f0 100755
--- a/Test/runtests
+++ b/Test/runtests
@@ -86,6 +86,13 @@
diff -b $BASEDIR/hlsl.hlslOffset.vert.out $TARGETDIR/hlsl.hlslOffset.vert.out || HASERROR=1
#
+# Tesing --resource-set-binding
+#
+echo Configuring HLSL descriptor set and binding number manually
+$EXE -V -D -e main -H hlsl.multiDescriptorSet.frag --rsb frag t0 0 0 t1 1 0 s0 0 1 s1 1 1 b0 2 0 b1 2 1 b2 2 2 > $TARGETDIR/hlsl.multiDescriptorSet.frag.out
+diff -b $BASEDIR/hlsl.multiDescriptorSet.frag.out $TARGETDIR/hlsl.multiDescriptorSet.frag.out
+
+#
# Final checking
#
if [ $HASERROR -eq 0 ]
diff --git a/glslang/MachineIndependent/ShaderLang.cpp b/glslang/MachineIndependent/ShaderLang.cpp
index de8dd6a..5563da8 100644
--- a/glslang/MachineIndependent/ShaderLang.cpp
+++ b/glslang/MachineIndependent/ShaderLang.cpp
@@ -1575,6 +1575,7 @@
void TShader::setHlslIoMapping(bool hlslIoMap) { intermediate->setHlslIoMapping(hlslIoMap); }
void TShader::setFlattenUniformArrays(bool flatten) { intermediate->setFlattenUniformArrays(flatten); }
void TShader::setNoStorageFormat(bool useUnknownFormat) { intermediate->setNoStorageFormat(useUnknownFormat); }
+void TShader::setResourceSetBinding(const std::vector<std::string>& base) { intermediate->setResourceSetBinding(base); }
//
// Turn the shader strings into a parse tree in the TIntermediate.
diff --git a/glslang/MachineIndependent/iomapper.cpp b/glslang/MachineIndependent/iomapper.cpp
index e68e0f8..02fdf04 100644
--- a/glslang/MachineIndependent/iomapper.cpp
+++ b/glslang/MachineIndependent/iomapper.cpp
@@ -349,6 +349,7 @@
int baseUboBinding;
int baseSsboBinding;
int baseUavBinding;
+ std::vector<std::string> baseResourceSetBinding;
bool doAutoMapping;
typedef std::vector<int> TSlotSet;
typedef std::unordered_map<int, TSlotSet> TSlotSetMap;
@@ -656,6 +657,7 @@
intermediate.getShiftUboBinding() == 0 &&
intermediate.getShiftSsboBinding() == 0 &&
intermediate.getShiftUavBinding() == 0 &&
+ intermediate.getResourceSetBinding().empty() &&
intermediate.getAutoMapBindings() == false &&
resolver == nullptr)
return true;
@@ -686,6 +688,7 @@
resolverBase->baseUboBinding = intermediate.getShiftUboBinding();
resolverBase->baseSsboBinding = intermediate.getShiftSsboBinding();
resolverBase->baseUavBinding = intermediate.getShiftUavBinding();
+ resolverBase->baseResourceSetBinding = intermediate.getResourceSetBinding();
resolverBase->doAutoMapping = intermediate.getAutoMapBindings();
resolver = resolverBase;
diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h
index 2fd2e9f..da77a5b 100644
--- a/glslang/MachineIndependent/localintermediate.h
+++ b/glslang/MachineIndependent/localintermediate.h
@@ -216,6 +216,8 @@
unsigned int getShiftSsboBinding() const { return shiftSsboBinding; }
void setShiftUavBinding(unsigned int shift) { shiftUavBinding = shift; }
unsigned int getShiftUavBinding() const { return shiftUavBinding; }
+ void setResourceSetBinding(const std::vector<std::string>& shift) { resourceSetBinding = shift; }
+ const std::vector<std::string>& getResourceSetBinding() const { return resourceSetBinding; }
void setAutoMapBindings(bool map) { autoMapBindings = map; }
bool getAutoMapBindings() const { return autoMapBindings; }
void setFlattenUniformArrays(bool flatten) { flattenUniformArrays = flatten; }
@@ -512,6 +514,7 @@
unsigned int shiftUboBinding;
unsigned int shiftSsboBinding;
unsigned int shiftUavBinding;
+ std::vector<std::string> resourceSetBinding;
bool autoMapBindings;
bool flattenUniformArrays;
bool useUnknownFormat;
diff --git a/glslang/Public/ShaderLang.h b/glslang/Public/ShaderLang.h
index c2aa1ad..42e4a46 100644
--- a/glslang/Public/ShaderLang.h
+++ b/glslang/Public/ShaderLang.h
@@ -40,6 +40,7 @@
#include "../MachineIndependent/Versions.h"
#include <cstring>
+#include <vector>
#ifdef _WIN32
#define C_DECL __cdecl
@@ -306,6 +307,7 @@
void setShiftUavBinding(unsigned int base);
void setShiftCbufferBinding(unsigned int base); // synonym for setShiftUboBinding
void setShiftSsboBinding(unsigned int base);
+ void setResourceSetBinding(const std::vector<std::string>& base);
void setAutoMapBindings(bool map);
void setHlslIoMapping(bool hlslIoMap);
void setFlattenUniformArrays(bool flatten);
diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp
index 6129dde..e9a781e 100644
--- a/gtests/Hlsl.FromFile.cpp
+++ b/gtests/Hlsl.FromFile.cpp
@@ -285,7 +285,7 @@
{"hlsl.typeGraphCopy.vert", "main"},
{"hlsl.typedef.frag", "PixelShaderFunction"},
{"hlsl.whileLoop.frag", "PixelShaderFunction"},
- {"hlsl.void.frag", "PixelShaderFunction"},
+ {"hlsl.void.frag", "PixelShaderFunction"}
}),
FileNameAsCustomTestSuffix
);
diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp
index 6d96377..f970453 100755
--- a/hlsl/hlslParseHelper.cpp
+++ b/hlsl/hlslParseHelper.cpp
@@ -4821,6 +4821,7 @@
}
// TODO: learn what all these really mean and how they interact with regNumber and subComponent
+ std::vector<std::string> resourceInfo = intermediate.getResourceSetBinding();
switch (std::tolower(desc[0])) {
case 'b':
case 't':
@@ -4828,6 +4829,13 @@
case 's':
case 'u':
qualifier.layoutBinding = regNumber + subComponent;
+ for (auto it = resourceInfo.cbegin(); it != resourceInfo.cend(); it = it + 3) {
+ if (strcmp(desc.c_str(), it[0].c_str()) == 0) {
+ qualifier.layoutSet = atoi(it[1].c_str());
+ qualifier.layoutBinding = atoi(it[2].c_str()) + subComponent;
+ break;
+ }
+ }
break;
default:
warn(loc, "ignoring unrecognized register type", "register", "%c", desc[0]);