HLSL: Additional attribute support: [[]], namespace, parameters:
authorJohn Kessenich <cepheus@frii.com>
Sat, 30 Sep 2017 20:34:50 +0000 (14:34 -0600)
committerJohn Kessenich <cepheus@frii.com>
Sat, 30 Sep 2017 20:34:50 +0000 (14:34 -0600)
- support C++11 style brackets [[...]]
- support namespaces [[vk::...]]
- support these on parameter declarations in functions
- support location, binding/set, input attachments

Test/baseResults/hlsl.attributeC11.frag.out [new file with mode: 0755]
Test/hlsl.attributeC11.frag [new file with mode: 0644]
gtests/Hlsl.FromFile.cpp
hlsl/hlslAttributes.cpp
hlsl/hlslAttributes.h
hlsl/hlslGrammar.cpp
hlsl/hlslParseHelper.cpp
hlsl/hlslParseHelper.h

diff --git a/Test/baseResults/hlsl.attributeC11.frag.out b/Test/baseResults/hlsl.attributeC11.frag.out
new file mode 100755 (executable)
index 0000000..ac58bf1
--- /dev/null
@@ -0,0 +1,176 @@
+hlsl.attributeC11.frag
+Shader version: 500
+gl_FragCoord origin is upper left
+0:? Sequence
+0:16  Function Definition: @main(vf4; ( temp 4-component vector of float)
+0:16    Function Parameters: 
+0:16      'input' ( in 4-component vector of float)
+0:?     Sequence
+0:17      Branch: Return with expression
+0:17        add ( temp 4-component vector of float)
+0:17          'input' ( in 4-component vector of float)
+0:17          textureFetch ( temp 4-component vector of float)
+0:17            'attach' ( uniform texture2D)
+0:17            vector swizzle ( temp int)
+0:17              Constant:
+0:17                0 (const int)
+0:17                0 (const int)
+0:17              Sequence
+0:17                Constant:
+0:17                  0 (const int)
+0:17            direct index ( temp int)
+0:17              Constant:
+0:17                0 (const int)
+0:17                0 (const int)
+0:17              Constant:
+0:17                1 (const int)
+0:16  Function Definition: main( ( temp void)
+0:16    Function Parameters: 
+0:?     Sequence
+0:16      move second child to first child ( temp 4-component vector of float)
+0:?         'input' ( temp 4-component vector of float)
+0:?         'input' (layout( location=8) in 4-component vector of float)
+0:16      move second child to first child ( temp 4-component vector of float)
+0:?         '@entryPointOutput' (layout( location=7) out 4-component vector of float)
+0:16        Function Call: @main(vf4; ( temp 4-component vector of float)
+0:?           'input' ( temp 4-component vector of float)
+0:?   Linker Objects
+0:?     'buffer1' (layout( set=0 binding=1 row_major std430) readonly buffer block{layout( row_major std430) buffer implicitly-sized array of structure{ temp 2-component vector of float f} @data})
+0:?     'buffer3' (layout( set=2 binding=3 row_major std430) readonly buffer block{layout( row_major std430) buffer implicitly-sized array of structure{ temp 2-component vector of float f} @data})
+0:?     'attach' ( uniform texture2D)
+0:?     '@entryPointOutput' (layout( location=7) out 4-component vector of float)
+0:?     'input' (layout( location=8) in 4-component vector of float)
+
+
+Linked fragment stage:
+
+
+Shader version: 500
+gl_FragCoord origin is upper left
+0:? Sequence
+0:16  Function Definition: @main(vf4; ( temp 4-component vector of float)
+0:16    Function Parameters: 
+0:16      'input' ( in 4-component vector of float)
+0:?     Sequence
+0:17      Branch: Return with expression
+0:17        add ( temp 4-component vector of float)
+0:17          'input' ( in 4-component vector of float)
+0:17          textureFetch ( temp 4-component vector of float)
+0:17            'attach' ( uniform texture2D)
+0:17            vector swizzle ( temp int)
+0:17              Constant:
+0:17                0 (const int)
+0:17                0 (const int)
+0:17              Sequence
+0:17                Constant:
+0:17                  0 (const int)
+0:17            direct index ( temp int)
+0:17              Constant:
+0:17                0 (const int)
+0:17                0 (const int)
+0:17              Constant:
+0:17                1 (const int)
+0:16  Function Definition: main( ( temp void)
+0:16    Function Parameters: 
+0:?     Sequence
+0:16      move second child to first child ( temp 4-component vector of float)
+0:?         'input' ( temp 4-component vector of float)
+0:?         'input' (layout( location=8) in 4-component vector of float)
+0:16      move second child to first child ( temp 4-component vector of float)
+0:?         '@entryPointOutput' (layout( location=7) out 4-component vector of float)
+0:16        Function Call: @main(vf4; ( temp 4-component vector of float)
+0:?           'input' ( temp 4-component vector of float)
+0:?   Linker Objects
+0:?     'buffer1' (layout( set=0 binding=1 row_major std430) readonly buffer block{layout( row_major std430) buffer implicitly-sized array of structure{ temp 2-component vector of float f} @data})
+0:?     'buffer3' (layout( set=2 binding=3 row_major std430) readonly buffer block{layout( row_major std430) buffer implicitly-sized array of structure{ temp 2-component vector of float f} @data})
+0:?     'attach' ( uniform texture2D)
+0:?     '@entryPointOutput' (layout( location=7) out 4-component vector of float)
+0:?     'input' (layout( location=8) in 4-component vector of float)
+
+// Module Version 10000
+// Generated by (magic number): 80001
+// Id's are bound by 47
+
+                              Capability Shader
+               1:             ExtInstImport  "GLSL.std.450"
+                              MemoryModel Logical GLSL450
+                              EntryPoint Fragment 4  "main" 33 36
+                              ExecutionMode 4 OriginUpperLeft
+                              Source HLSL 500
+                              Name 4  "main"
+                              Name 11  "@main(vf4;"
+                              Name 10  "input"
+                              Name 16  "attach"
+                              Name 31  "input"
+                              Name 33  "input"
+                              Name 36  "@entryPointOutput"
+                              Name 37  "param"
+                              Name 41  "S"
+                              MemberName 41(S) 0  "f"
+                              Name 43  "buffer1"
+                              MemberName 43(buffer1) 0  "@data"
+                              Name 45  "buffer1"
+                              Name 46  "buffer3"
+                              Decorate 16(attach) DescriptorSet 0
+                              Decorate 16(attach) InputAttachmentIndex 4
+                              Decorate 33(input) Location 8
+                              Decorate 36(@entryPointOutput) Location 7
+                              MemberDecorate 41(S) 0 Offset 0
+                              Decorate 42 ArrayStride 8
+                              MemberDecorate 43(buffer1) 0 NonWritable
+                              MemberDecorate 43(buffer1) 0 Offset 0
+                              Decorate 43(buffer1) BufferBlock
+                              Decorate 45(buffer1) DescriptorSet 0
+                              Decorate 45(buffer1) Binding 1
+                              Decorate 46(buffer3) DescriptorSet 2
+                              Decorate 46(buffer3) Binding 3
+               2:             TypeVoid
+               3:             TypeFunction 2
+               6:             TypeFloat 32
+               7:             TypeVector 6(float) 4
+               8:             TypePointer Function 7(fvec4)
+               9:             TypeFunction 7(fvec4) 8(ptr)
+              14:             TypeImage 6(float) 2D sampled format:Unknown
+              15:             TypePointer UniformConstant 14
+      16(attach):     15(ptr) Variable UniformConstant
+              18:             TypeInt 32 1
+              19:             TypeVector 18(int) 2
+              20:     18(int) Constant 0
+              21:   19(ivec2) ConstantComposite 20 20
+              22:             TypeInt 32 0
+              23:     22(int) Constant 0
+              25:     22(int) Constant 1
+              32:             TypePointer Input 7(fvec4)
+       33(input):     32(ptr) Variable Input
+              35:             TypePointer Output 7(fvec4)
+36(@entryPointOutput):     35(ptr) Variable Output
+              40:             TypeVector 6(float) 2
+           41(S):             TypeStruct 40(fvec2)
+              42:             TypeRuntimeArray 41(S)
+     43(buffer1):             TypeStruct 42
+              44:             TypePointer Uniform 43(buffer1)
+     45(buffer1):     44(ptr) Variable Uniform
+     46(buffer3):     44(ptr) Variable Uniform
+         4(main):           2 Function None 3
+               5:             Label
+       31(input):      8(ptr) Variable Function
+       37(param):      8(ptr) Variable Function
+              34:    7(fvec4) Load 33(input)
+                              Store 31(input) 34
+              38:    7(fvec4) Load 31(input)
+                              Store 37(param) 38
+              39:    7(fvec4) FunctionCall 11(@main(vf4;) 37(param)
+                              Store 36(@entryPointOutput) 39
+                              Return
+                              FunctionEnd
+  11(@main(vf4;):    7(fvec4) Function None 9
+       10(input):      8(ptr) FunctionParameter
+              12:             Label
+              13:    7(fvec4) Load 10(input)
+              17:          14 Load 16(attach)
+              24:     18(int) CompositeExtract 21 0
+              26:     18(int) CompositeExtract 21 1
+              27:    7(fvec4) ImageFetch 17 24 Lod 26
+              28:    7(fvec4) FAdd 13 27
+                              ReturnValue 28
+                              FunctionEnd
diff --git a/Test/hlsl.attributeC11.frag b/Test/hlsl.attributeC11.frag
new file mode 100644 (file)
index 0000000..4fe663a
--- /dev/null
@@ -0,0 +1,18 @@
+struct S {\r
+    float2 f;\r
+};\r
+\r
+[[vk::binding(1)]]\r
+StructuredBuffer<S> buffer1;\r
+\r
+[[vk::binding(3, 2)]]\r
+StructuredBuffer<S> buffer3;\r
+\r
+[[vk::input_attachment_index(4)]]\r
+Texture2D<float4> attach;\r
+\r
+[[vk::location(7)]] float4\r
+main([[vk::location(8)]] float4 input: A) : B\r
+{\r
+    return input + attach.Load(float2(0.5));\r
+}\r
index 4e810ded86ca5e184a2b404c805d182a0e044baf..dfdadf5eef1365839422b1cecd035005ade32208 100644 (file)
@@ -99,6 +99,7 @@ INSTANTIATE_TEST_CASE_P(
         {"hlsl.assoc.frag", "PixelShaderFunction"},
         {"hlsl.attribute.frag", "PixelShaderFunction"},
         {"hlsl.attribute.expression.comp", "main"},
+        {"hlsl.attributeC11.frag", "main"},
         {"hlsl.basic.comp", "main"},
         {"hlsl.basic.geom", "main"},
         {"hlsl.boolConv.vert", "main"},
index 14f7a7bd37c60ef554110a65a077cefb846bf3ee..61ef8055de7d656705bcb49c7b697d5e201c0b32 100644 (file)
 namespace glslang {
     // Map the given string to an attribute enum from TAttributeType,
     // or EatNone if invalid.
-    TAttributeType TAttributeMap::attributeFromName(const TString& name)
+    TAttributeType TAttributeMap::attributeFromName(const TString& nameSpace, const TString& name)
     {
         // These are case insensitive.
         TString lowername(name);
         std::transform(lowername.begin(), lowername.end(), lowername.begin(), ::tolower);
+        TString lowernameSpace(nameSpace);
+        std::transform(lowernameSpace.begin(), lowernameSpace.end(), lowernameSpace.begin(), ::tolower);
+
+        // handle names within a namespace
+
+        if (lowernameSpace == "vk") {
+            if (lowername == "input_attachment_index")
+                return EatInputAttachment;
+            else if (lowername == "location")
+                return EatLocation;
+            else if (lowername == "binding")
+                return EatBinding;
+        } else if (lowernameSpace.size() > 0)
+            return EatNone;
+
+        // handle names with no namespace
 
         if (lowername == "allow_uav_condition")
             return EatAllow_uav_condition;
@@ -88,12 +104,12 @@ namespace glslang {
 
     // Look up entry, inserting if it's not there, and if name is a valid attribute name
     // as known by attributeFromName.
-    TAttributeType TAttributeMap::setAttribute(const TString* name, TIntermAggregate* value)
+    TAttributeType TAttributeMap::setAttribute(const TString& nameSpace, const TString* name, TIntermAggregate* value)
     {
         if (name == nullptr)
             return EatNone;
 
-        const TAttributeType attr = attributeFromName(*name);
+        const TAttributeType attr = attributeFromName(nameSpace, *name);
 
         if (attr != EatNone)
             attributes[attr] = value;
index b32a53cbe3c80a54015af9589f71710679f16e55..16ec31dad346fce9825a0b20d39b5f0129b1ea7b 100644 (file)
@@ -63,6 +63,9 @@ namespace glslang {
         EatPatchSize,
         EatUnroll,
         EatLoop,
+        EatBinding,
+        EatLocation,
+        EatInputAttachment
     };
 }
 
@@ -82,7 +85,7 @@ namespace glslang {
     public:
         // Search for and potentially add the attribute into the map.  Return the
         // attribute type enum for it, if found, else EatNone.
-        TAttributeType setAttribute(const TString* name, TIntermAggregate* value);
+        TAttributeType setAttribute(const TString& nameSpace, const TString* name, TIntermAggregate* value);
 
         // Const lookup: search for (but do not modify) the attribute in the map.
         const TIntermAggregate* operator[](TAttributeType) const;
@@ -92,7 +95,7 @@ namespace glslang {
 
     protected:
         // Find an attribute enum given its name.
-        static TAttributeType attributeFromName(const TString&);
+        static TAttributeType attributeFromName(const TString& nameSpace, const TString& name);
 
         std::unordered_map<TAttributeType, TIntermAggregate*> attributes;
     };
index fcdeff403f2504f770fb2da62b2986c8eee2e88a..4914f20c14c6df9a56d9d425a60c36311ec69266 100755 (executable)
@@ -295,13 +295,16 @@ bool HlslGrammar::acceptSamplerDeclarationDX9(TType& /*type*/)
 }
 
 // declaration
+//      : attributes attributed_declaration
+//      | NAMESPACE IDENTIFIER LEFT_BRACE declaration_list RIGHT_BRACE
+//
+// attributed_declaration
 //      : sampler_declaration_dx9 post_decls SEMICOLON
 //      | fully_specified_type                           // for cbuffer/tbuffer
 //      | fully_specified_type declarator_list SEMICOLON // for non cbuffer/tbuffer
 //      | fully_specified_type identifier function_parameters post_decls compound_statement  // function definition
 //      | fully_specified_type identifier sampler_state post_decls compound_statement        // sampler definition
 //      | typedef declaration
-//      | NAMESPACE IDENTIFIER LEFT_BRACE declaration_list RIGHT_BRACE
 //
 // declarator_list
 //      : declarator COMMA declarator COMMA declarator...  // zero or more declarators
@@ -376,6 +379,8 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& nodeList)
     if (! acceptFullySpecifiedType(declaredType, nodeList))
         return false;
 
+    parseContext.transferTypeAttributes(declarator.attributes, declaredType);
+
     // cbuffer and tbuffer end with the closing '}'.
     // No semicolon is included.
     if (forbidDeclarators)
@@ -2371,16 +2376,25 @@ bool HlslGrammar::acceptDefaultParameterDeclaration(const TType& type, TIntermTy
 }
 
 // parameter_declaration
+//      : attributes attributed_declaration
+//
+// attributed_declaration
 //      : fully_specified_type post_decls [ = default_parameter_declaration ]
 //      | fully_specified_type identifier array_specifier post_decls [ = default_parameter_declaration ]
 //
 bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
 {
+    // attributes
+    TAttributeMap attributes;
+    acceptAttributes(attributes);
+
     // fully_specified_type
     TType* type = new TType;
     if (! acceptFullySpecifiedType(*type))
         return false;
 
+    parseContext.transferTypeAttributes(attributes, *type);
+
     // identifier
     HlslToken idToken;
     acceptIdentifier(idToken);
@@ -3256,7 +3270,15 @@ bool HlslGrammar::acceptStatement(TIntermNode*& statement)
 }
 
 // attributes
-//      : list of zero or more of:  LEFT_BRACKET attribute RIGHT_BRACKET
+//      : [zero or more:] bracketed-attribute
+//
+// bracketed-attribute:
+//      : LEFT_BRACKET scoped-attribute RIGHT_BRACKET
+//      : LEFT_BRACKET LEFT_BRACKET scoped-attribute RIGHT_BRACKET RIGHT_BRACKET
+//
+// scoped-attribute:
+//      : attribute
+//      | namespace COLON COLON attribute
 //
 // attribute:
 //      : UNROLL
@@ -3283,18 +3305,33 @@ void HlslGrammar::acceptAttributes(TAttributeMap& attributes)
     // numthreads, which is used to set the CS local size.
     // TODO: subset to correct set?  Pass on?
     do {
-        HlslToken idToken;
+        HlslToken attributeToken;
 
         // LEFT_BRACKET?
         if (! acceptTokenClass(EHTokLeftBracket))
             return;
+        // another LEFT_BRACKET?
+        bool doubleBrackets = false;
+        if (acceptTokenClass(EHTokLeftBracket))
+            doubleBrackets = true;
+
+        // attribute? (could be namespace; will adjust later)
+        if (!acceptIdentifier(attributeToken)) {
+            if (!peekTokenClass(EHTokRightBracket)) {
+                expected("namespace or attribute identifier");
+                advanceToken();
+            }
+        }
 
-        // attribute
-        if (acceptIdentifier(idToken)) {
-            // 'idToken.string' is the attribute
-        } else if (! peekTokenClass(EHTokRightBracket)) {
-            expected("identifier");
-            advanceToken();
+        TString nameSpace;
+        if (acceptTokenClass(EHTokColonColon)) {
+            // namespace COLON COLON
+            nameSpace = *attributeToken.string;
+            // attribute
+            if (!acceptIdentifier(attributeToken)) {
+                expected("attribute identifier");
+                return;
+            }
         }
 
         TIntermAggregate* expressions = nullptr;
@@ -3327,10 +3364,15 @@ void HlslGrammar::acceptAttributes(TAttributeMap& attributes)
             expected("]");
             return;
         }
+        // another RIGHT_BRACKET?
+        if (doubleBrackets && !acceptTokenClass(EHTokRightBracket)) {
+            expected("]]");
+            return;
+        }
 
         // Add any values we found into the attribute map.  This accepts
         // (and ignores) values not mapping to a known TAttributeType;
-        attributes.setAttribute(idToken.string, expressions);
+        attributes.setAttribute(nameSpace, attributeToken.string, expressions);
     } while (true);
 }
 
index 6f023de58552fa2dd569f73423cc270b4826e40d..74afb031ce4504f15cd2e4290661277a7f37b260 100755 (executable)
@@ -1666,7 +1666,6 @@ TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& l
     return paramNodes;
 }
 
-
 // Handle all [attrib] attribute for the shader entry point
 void HlslParseContext::handleEntryPointAttributes(const TSourceLoc& loc, const TAttributeMap& attributes)
 {
@@ -1815,6 +1814,44 @@ void HlslParseContext::handleEntryPointAttributes(const TSourceLoc& loc, const T
     }
 }
 
+// Update the given type with any type-like attribute information in the
+// attributes.
+void HlslParseContext::transferTypeAttributes(const TAttributeMap& attributes, TType& type)
+{
+    // extract integers out of attribute arguments stored in attribute aggregate
+    const auto getInt = [&](TAttributeType attr, int argNum, int& value) -> bool {
+        const TIntermAggregate* attrAgg = attributes[attr];
+        if (attrAgg == nullptr)
+            return false;
+        if (argNum >= attrAgg->getSequence().size())
+            return false;
+        const TConstUnion& intConst = attrAgg->getSequence()[argNum]->getAsConstantUnion()->getConstArray()[0];
+        if (intConst == nullptr)
+            return false;
+        value = intConst.getIConst();
+        return true;
+    };
+
+    // location
+    int value;
+    if (getInt(EatLocation, 0, value))
+        type.getQualifier().layoutLocation = value;
+
+    // binding
+    if (getInt(EatBinding, 0, value)) {
+        type.getQualifier().layoutBinding = value;
+        type.getQualifier().layoutSet = 0;
+    }
+
+    // set
+    if (getInt(EatBinding, 1, value))
+        type.getQualifier().layoutSet = value;
+
+    // input attachment
+    if (getInt(EatInputAttachment, 0, value))
+        type.getQualifier().layoutAttachment = value;
+}
+
 //
 // Do all special handling for the entry point, including wrapping
 // the shader's entry point with the official entry point that will call it.
index 077beb918531fa9019a88fa872acc1ed505c6c41..c1468ed0752dd157f4e9e23821bcd7b8b10ac01d 100755 (executable)
@@ -83,6 +83,7 @@ public:
     TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&, const TAttributeMap&, TIntermNode*& entryPointTree);
     TIntermNode* transformEntryPoint(const TSourceLoc&, TFunction&, const TAttributeMap&);
     void handleEntryPointAttributes(const TSourceLoc&, const TAttributeMap&);
+    void transferTypeAttributes(const TAttributeMap&, TType&);
     void handleFunctionBody(const TSourceLoc&, TFunction&, TIntermNode* functionBody, TIntermNode*& node);
     void remapEntryPointIO(TFunction& function, TVariable*& returnValue, TVector<TVariable*>& inputs, TVector<TVariable*>& outputs);
     void remapNonEntryPointIO(TFunction& function);