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]);