diff --git a/Test/baseResults/hlsl.basic.geom.out b/Test/baseResults/hlsl.basic.geom.out
new file mode 100644
index 0000000000000000000000000000000000000000..2c20b439c149f92d10605059be4a6f00d004699f
--- /dev/null
+++ b/Test/baseResults/hlsl.basic.geom.out
@@ -0,0 +1,201 @@
+hlsl.basic.geom
+Shader version: 450
+invocations = -1
+max_vertices = 4
+input primitive = triangles
+output primitive = line_strip
+0:? Sequence
+0:16  Function Definition: main(u1[3];u1[3];struct-PSInput-f1-i11; (temp void)
+0:16    Function Parameters: 
+0:16      'VertexID' (layout(location=0 ) in 3-element array of uint)
+0:16      'test' (layout(location=3 ) in 3-element array of uint)
+0:16      'OutputStream' (out structure{temp float myfloat, temp int something})
+0:?     Sequence
+0:19      move second child to first child (temp float)
+0:19        myfloat: direct index for structure (temp float)
+0:19          'Vert' (temp structure{temp float myfloat, temp int something})
+0:19          Constant:
+0:19            0 (const int)
+0:19        Convert uint to float (temp float)
+0:19          add (temp uint)
+0:19            add (temp uint)
+0:19              direct index (layout(location=3 ) temp uint)
+0:19                'test' (layout(location=3 ) in 3-element array of uint)
+0:19                Constant:
+0:19                  0 (const int)
+0:19              direct index (layout(location=3 ) temp uint)
+0:19                'test' (layout(location=3 ) in 3-element array of uint)
+0:19                Constant:
+0:19                  1 (const int)
+0:19            direct index (layout(location=3 ) temp uint)
+0:19              'test' (layout(location=3 ) in 3-element array of uint)
+0:19              Constant:
+0:19                2 (const int)
+0:20      move second child to first child (temp int)
+0:20        something: direct index for structure (temp int)
+0:20          'Vert' (temp structure{temp float myfloat, temp int something})
+0:20          Constant:
+0:20            1 (const int)
+0:20        Convert uint to int (temp int)
+0:20          direct index (layout(location=0 ) temp uint)
+0:20            'VertexID' (layout(location=0 ) in 3-element array of uint)
+0:20            Constant:
+0:20              0 (const int)
+0:22      Sequence
+0:22        move second child to first child (temp structure{temp float myfloat, temp int something})
+0:22          'OutputStream' (out structure{temp float myfloat, temp int something})
+0:22          'Vert' (temp structure{temp float myfloat, temp int something})
+0:22        EmitVertex (temp void)
+0:23      Sequence
+0:23        move second child to first child (temp structure{temp float myfloat, temp int something})
+0:23          'OutputStream' (out structure{temp float myfloat, temp int something})
+0:23          'Vert' (temp structure{temp float myfloat, temp int something})
+0:23        EmitVertex (temp void)
+0:24      EndPrimitive (temp void)
+0:?   Linker Objects
+0:?     'VertexID' (layout(location=0 ) in 3-element array of uint)
+0:?     'test' (layout(location=3 ) in 3-element array of uint)
+0:?     'myfloat' (layout(location=0 ) out float)
+0:?     'something' (layout(location=1 ) out int)
+
+
+Linked geometry stage:
+
+
+Shader version: 450
+invocations = 1
+max_vertices = 4
+input primitive = triangles
+output primitive = line_strip
+0:? Sequence
+0:16  Function Definition: main(u1[3];u1[3];struct-PSInput-f1-i11; (temp void)
+0:16    Function Parameters: 
+0:16      'VertexID' (layout(location=0 ) in 3-element array of uint)
+0:16      'test' (layout(location=3 ) in 3-element array of uint)
+0:16      'OutputStream' (out structure{temp float myfloat, temp int something})
+0:?     Sequence
+0:19      move second child to first child (temp float)
+0:19        myfloat: direct index for structure (temp float)
+0:19          'Vert' (temp structure{temp float myfloat, temp int something})
+0:19          Constant:
+0:19            0 (const int)
+0:19        Convert uint to float (temp float)
+0:19          add (temp uint)
+0:19            add (temp uint)
+0:19              direct index (layout(location=3 ) temp uint)
+0:19                'test' (layout(location=3 ) in 3-element array of uint)
+0:19                Constant:
+0:19                  0 (const int)
+0:19              direct index (layout(location=3 ) temp uint)
+0:19                'test' (layout(location=3 ) in 3-element array of uint)
+0:19                Constant:
+0:19                  1 (const int)
+0:19            direct index (layout(location=3 ) temp uint)
+0:19              'test' (layout(location=3 ) in 3-element array of uint)
+0:19              Constant:
+0:19                2 (const int)
+0:20      move second child to first child (temp int)
+0:20        something: direct index for structure (temp int)
+0:20          'Vert' (temp structure{temp float myfloat, temp int something})
+0:20          Constant:
+0:20            1 (const int)
+0:20        Convert uint to int (temp int)
+0:20          direct index (layout(location=0 ) temp uint)
+0:20            'VertexID' (layout(location=0 ) in 3-element array of uint)
+0:20            Constant:
+0:20              0 (const int)
+0:22      Sequence
+0:22        move second child to first child (temp structure{temp float myfloat, temp int something})
+0:22          'OutputStream' (out structure{temp float myfloat, temp int something})
+0:22          'Vert' (temp structure{temp float myfloat, temp int something})
+0:22        EmitVertex (temp void)
+0:23      Sequence
+0:23        move second child to first child (temp structure{temp float myfloat, temp int something})
+0:23          'OutputStream' (out structure{temp float myfloat, temp int something})
+0:23          'Vert' (temp structure{temp float myfloat, temp int something})
+0:23        EmitVertex (temp void)
+0:24      EndPrimitive (temp void)
+0:?   Linker Objects
+0:?     'VertexID' (layout(location=0 ) in 3-element array of uint)
+0:?     'test' (layout(location=3 ) in 3-element array of uint)
+0:?     'myfloat' (layout(location=0 ) out float)
+0:?     'something' (layout(location=1 ) out int)
+
+// Module Version 10000
+// Generated by (magic number): 80001
+// Id's are bound by 45
+
+                              Capability Geometry
+               1:             ExtInstImport  "GLSL.std.450"
+                              MemoryModel Logical GLSL450
+                              EntryPoint Geometry 4  "main" 16 31 38 42 44
+                              ExecutionMode 4 Triangles
+                              ExecutionMode 4 Invocations 1
+                              ExecutionMode 4 OutputLineStrip
+                              ExecutionMode 4 OutputVertices 4
+                              Name 4  "main"
+                              Name 8  "PSInput"
+                              MemberName 8(PSInput) 0  "myfloat"
+                              MemberName 8(PSInput) 1  "something"
+                              Name 10  "Vert"
+                              Name 16  "test"
+                              Name 31  "VertexID"
+                              Name 38  "OutputStream"
+                              Name 42  "myfloat"
+                              Name 44  "something"
+                              Decorate 16(test) Location 3
+                              Decorate 31(VertexID) Location 0
+                              Decorate 42(myfloat) Location 0
+                              Decorate 44(something) Location 1
+               2:             TypeVoid
+               3:             TypeFunction 2
+               6:             TypeFloat 32
+               7:             TypeInt 32 1
+      8(PSInput):             TypeStruct 6(float) 7(int)
+               9:             TypePointer Function 8(PSInput)
+              11:      7(int) Constant 0
+              12:             TypeInt 32 0
+              13:     12(int) Constant 3
+              14:             TypeArray 12(int) 13
+              15:             TypePointer Input 14
+        16(test):     15(ptr) Variable Input
+              17:             TypePointer Input 12(int)
+              20:      7(int) Constant 1
+              24:      7(int) Constant 2
+              29:             TypePointer Function 6(float)
+    31(VertexID):     15(ptr) Variable Input
+              35:             TypePointer Function 7(int)
+              37:             TypePointer Output 8(PSInput)
+38(OutputStream):     37(ptr) Variable Output
+              41:             TypePointer Output 6(float)
+     42(myfloat):     41(ptr) Variable Output
+              43:             TypePointer Output 7(int)
+   44(something):     43(ptr) Variable Output
+         4(main):           2 Function None 3
+               5:             Label
+        10(Vert):      9(ptr) Variable Function
+              18:     17(ptr) AccessChain 16(test) 11
+              19:     12(int) Load 18
+              21:     17(ptr) AccessChain 16(test) 20
+              22:     12(int) Load 21
+              23:     12(int) IAdd 19 22
+              25:     17(ptr) AccessChain 16(test) 24
+              26:     12(int) Load 25
+              27:     12(int) IAdd 23 26
+              28:    6(float) ConvertUToF 27
+              30:     29(ptr) AccessChain 10(Vert) 11
+                              Store 30 28
+              32:     17(ptr) AccessChain 31(VertexID) 11
+              33:     12(int) Load 32
+              34:      7(int) Bitcast 33
+              36:     35(ptr) AccessChain 10(Vert) 20
+                              Store 36 34
+              39:  8(PSInput) Load 10(Vert)
+                              Store 38(OutputStream) 39
+                              EmitVertex
+              40:  8(PSInput) Load 10(Vert)
+                              Store 38(OutputStream) 40
+                              EmitVertex
+                              EndPrimitive
+                              Return
+                              FunctionEnd
diff --git a/Test/hlsl.basic.geom b/Test/hlsl.basic.geom
new file mode 100644
index 0000000000000000000000000000000000000000..79b061ee0af1853b82c62201c50bbe3fc18815cf
--- /dev/null
+++ b/Test/hlsl.basic.geom
@@ -0,0 +1,25 @@
+struct PSInput
+{
+    float  myfloat    : SOME_SEMANTIC;
+    int    something  : ANOTHER_SEMANTIC;
+};
+
+struct nametest {
+    int Append;        // these are valid names even though they are also method names.
+    int RestartStrip;  // ...
+};
+
+[maxvertexcount(4)]
+void main(triangle in uint VertexID[3] : VertexID,
+          triangle uint test[3] : FOO, 
+          inout LineStream<PSInput> OutputStream)
+{
+    PSInput Vert;
+
+    Vert.myfloat    = test[0] + test[1] + test[2];
+    Vert.something  = VertexID[0];
+
+    OutputStream.Append(Vert);
+    OutputStream.Append(Vert);
+    OutputStream.RestartStrip();
+}
diff --git a/glslang/Include/intermediate.h b/glslang/Include/intermediate.h
index db61b750778b2225a4757d4ff99d3096b010c4a5..8f7ffcc0daa308cc9dc3c25bf421cd91e1e4900b 100644
--- a/glslang/Include/intermediate.h
+++ b/glslang/Include/intermediate.h
@@ -621,6 +621,10 @@ enum TOperator {
     EOpMethodGatherCmpGreen,             // ...
     EOpMethodGatherCmpBlue,              // ...
     EOpMethodGatherCmpAlpha,             // ...
+
+    // geometry methods
+    EOpMethodAppend,                     // Geometry shader methods
+    EOpMethodRestartStrip,               // ...
 };
 
 class TIntermTraverser;
diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp
index 5487fb98eae187e5286e0c7054fe7c0d4da4e495..2867140e338187db027f8c9af10d7b520a52765b 100644
--- a/gtests/Hlsl.FromFile.cpp
+++ b/gtests/Hlsl.FromFile.cpp
@@ -88,6 +88,7 @@ INSTANTIATE_TEST_CASE_P(
         {"hlsl.attribute.frag", "PixelShaderFunction"},
         {"hlsl.attribute.expression.comp", "main"},
         {"hlsl.basic.comp", "main"},
+        {"hlsl.basic.geom", "main"},
         {"hlsl.buffer.frag", "PixelShaderFunction"},
         {"hlsl.calculatelod.dx10.frag", "main"},
         {"hlsl.calculatelodunclamped.dx10.frag", "main"},
diff --git a/hlsl/hlslAttributes.cpp b/hlsl/hlslAttributes.cpp
index 957f282eed9aa4140753362c26875c2983fc9b25..966ff35210152713c2b761c71bc5a123a9822b0f 100644
--- a/hlsl/hlslAttributes.cpp
+++ b/hlsl/hlslAttributes.cpp
@@ -55,27 +55,29 @@ namespace glslang {
         else if (lowername == "domain")
             return EatDomain;
         else if (lowername == "earlydepthstencil")
-            return EatEarlydepthstencil;
+            return EatEarlyDepthStencil;
         else if (lowername == "fastopt")
-            return EatFastopt;
+            return EatFastOpt;
         else if (lowername == "flatten")
             return EatFlatten;
         else if (lowername == "forcecase")
-            return EatForcecase;
+            return EatForceCase;
         else if (lowername == "instance")
             return EatInstance;
         else if (lowername == "maxtessfactor")
-            return EatMaxtessfactor;
+            return EatMaxTessFactor;
+        else if (lowername == "maxvertexcount")
+            return EatMaxVertexCount;
         else if (lowername == "numthreads")
-            return EatNumthreads;
+            return EatNumThreads;
         else if (lowername == "outputcontrolpoints")
-            return EatOutputcontrolpoints;
+            return EatOutputControlPoints;
         else if (lowername == "outputtopology")
-            return EatOutputtopology;
+            return EatOutputTopology;
         else if (lowername == "partitioning")
             return EatPartitioning;
         else if (lowername == "patchconstantfunc")
-            return EatPatchconstantfunc;
+            return EatPatchConstantFunc;
         else if (lowername == "unroll")
             return EatUnroll;
         else
diff --git a/hlsl/hlslAttributes.h b/hlsl/hlslAttributes.h
index da5ee5ef72bb7fb5fe756e820bae3d11993607e8..312a4564262277952d145914977adfc6f49e566b 100644
--- a/hlsl/hlslAttributes.h
+++ b/hlsl/hlslAttributes.h
@@ -48,17 +48,18 @@ namespace glslang {
         EatBranch,
         EatCall,
         EatDomain,
-        EatEarlydepthstencil,
-        EatFastopt,
+        EatEarlyDepthStencil,
+        EatFastOpt,
         EatFlatten,
-        EatForcecase,
+        EatForceCase,
         EatInstance,
-        EatMaxtessfactor,
-        EatNumthreads,
-        EatOutputcontrolpoints,
-        EatOutputtopology,
+        EatMaxTessFactor,
+        EatNumThreads,
+        EatMaxVertexCount,
+        EatOutputControlPoints,
+        EatOutputTopology,
         EatPartitioning,
-        EatPatchconstantfunc,
+        EatPatchConstantFunc,
         EatUnroll,
     };
 }
diff --git a/hlsl/hlslGrammar.cpp b/hlsl/hlslGrammar.cpp
index e6f4b60372d2a2ad0bc2b3b2f38cee6e7777353e..b2715eda84ce33eedf9d538b32fbe675774c9e42 100755
--- a/hlsl/hlslGrammar.cpp
+++ b/hlsl/hlslGrammar.cpp
@@ -469,9 +469,14 @@ bool HlslGrammar::acceptFullySpecifiedType(TType& type)
         // Some qualifiers are set when parsing the type.  Merge those with
         // whatever comes from acceptQualifier.
         assert(qualifier.layoutFormat == ElfNone);
+
         qualifier.layoutFormat = type.getQualifier().layoutFormat;
         qualifier.precision    = type.getQualifier().precision;
-        type.getQualifier() = qualifier;
+
+        if (type.getQualifier().storage == EvqVaryingOut)
+            qualifier.storage      = type.getQualifier().storage;
+
+        type.getQualifier()    = qualifier;
     }
 
     return true;
@@ -544,6 +549,35 @@ bool HlslGrammar::acceptQualifier(TQualifier& qualifier)
             if (! acceptLayoutQualifierList(qualifier))
                 return false;
             continue;
+
+        // GS geometries: these are specified on stage input variables, and are an error (not verified here)
+        // for output variables.
+        case EHTokPoint:
+            qualifier.storage = EvqIn;
+            if (!parseContext.handleInputGeometry(token.loc, ElgPoints))
+                return false;
+            break;
+        case EHTokLine:
+            qualifier.storage = EvqIn;
+            if (!parseContext.handleInputGeometry(token.loc, ElgLines))
+                return false;
+            break;
+        case EHTokTriangle:
+            qualifier.storage = EvqIn;
+            if (!parseContext.handleInputGeometry(token.loc, ElgTriangles))
+                return false;
+            break;
+        case EHTokLineAdj:
+            qualifier.storage = EvqIn;
+            if (!parseContext.handleInputGeometry(token.loc, ElgLinesAdjacency))
+                return false;
+            break; 
+        case EHTokTriangleAdj:
+            qualifier.storage = EvqIn;
+            if (!parseContext.handleInputGeometry(token.loc, ElgTrianglesAdjacency))
+                return false;
+            break; 
+            
         default:
             return true;
         }
@@ -608,7 +642,7 @@ bool HlslGrammar::acceptLayoutQualifierList(TQualifier& qualifier)
 //      | UINT
 //      | BOOL
 //
-bool HlslGrammar::acceptTemplateType(TBasicType& basicType)
+bool HlslGrammar::acceptTemplateVecMatBasicType(TBasicType& basicType)
 {
     switch (peek()) {
     case EHTokFloat:
@@ -652,7 +686,7 @@ bool HlslGrammar::acceptVectorTemplateType(TType& type)
     }
 
     TBasicType basicType;
-    if (! acceptTemplateType(basicType)) {
+    if (! acceptTemplateVecMatBasicType(basicType)) {
         expected("scalar type");
         return false;
     }
@@ -704,7 +738,7 @@ bool HlslGrammar::acceptMatrixTemplateType(TType& type)
     }
 
     TBasicType basicType;
-    if (! acceptTemplateType(basicType)) {
+    if (! acceptTemplateVecMatBasicType(basicType)) {
         expected("scalar type");
         return false;
     }
@@ -753,6 +787,56 @@ bool HlslGrammar::acceptMatrixTemplateType(TType& type)
     return true;
 }
 
+// layout_geometry
+//      : LINESTREAM
+//      | POINTSTREAM
+//      | TRIANGLESTREAM
+//
+bool HlslGrammar::acceptOutputPrimitiveGeometry(TLayoutGeometry& geometry)
+{
+    // read geometry type
+    const EHlslTokenClass geometryType = peek();
+
+    switch (geometryType) {
+    case EHTokPointStream:    geometry = ElgPoints;        break;
+    case EHTokLineStream:     geometry = ElgLineStrip;     break;
+    case EHTokTriangleStream: geometry = ElgTriangleStrip; break;
+    default:
+        return false;  // not a layout geometry
+    }
+
+    advanceToken();  // consume the layout keyword
+    return true;
+}
+
+// stream_out_template_type
+//      : output_primitive_geometry_type LEFT_ANGLE type RIGHT_ANGLE
+//
+bool HlslGrammar::acceptStreamOutTemplateType(TType& type, TLayoutGeometry& geometry)
+{
+    geometry = ElgNone;
+
+    if (! acceptOutputPrimitiveGeometry(geometry))
+        return false;
+
+    if (! acceptTokenClass(EHTokLeftAngle))
+        return false;
+    
+    if (! acceptType(type)) {
+        expected("stream output type");
+        return false;
+    }
+
+    type.getQualifier().storage = EvqVaryingOut;
+
+    if (! acceptTokenClass(EHTokRightAngle)) {
+        expected("right angle bracket");
+        return false;
+    }
+
+    return true;
+}
+    
 // annotations
 //      : LEFT_ANGLE declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
 //
@@ -989,6 +1073,20 @@ bool HlslGrammar::acceptType(TType& type)
         return acceptMatrixTemplateType(type);
         break;
 
+    case EHTokPointStream:            // fall through
+    case EHTokLineStream:             // ...
+    case EHTokTriangleStream:         // ...
+        {
+            TLayoutGeometry geometry;
+            if (! acceptStreamOutTemplateType(type, geometry))
+                return false;
+
+            if (! parseContext.handleOutputGeometry(token.loc, geometry))
+                return false;
+            
+            return true;
+        }
+
     case EHTokSampler:                // fall through
     case EHTokSampler1d:              // ...
     case EHTokSampler2d:              // ...
diff --git a/hlsl/hlslGrammar.h b/hlsl/hlslGrammar.h
index c3e42f674e66cd962f83c509753aa846b52dac98..8804b217ec76ebdb1d11abac98ba299627cef68b 100755
--- a/hlsl/hlslGrammar.h
+++ b/hlsl/hlslGrammar.h
@@ -72,9 +72,11 @@ namespace glslang {
         bool acceptQualifier(TQualifier&);
         bool acceptLayoutQualifierList(TQualifier&);
         bool acceptType(TType&);
-        bool acceptTemplateType(TBasicType&);
+        bool acceptTemplateVecMatBasicType(TBasicType&);
         bool acceptVectorTemplateType(TType&);
         bool acceptMatrixTemplateType(TType&);
+        bool acceptStreamOutTemplateType(TType&, TLayoutGeometry&);
+        bool acceptOutputPrimitiveGeometry(TLayoutGeometry&);
         bool acceptAnnotations(TQualifier&);
         bool acceptSamplerType(TType&);
         bool acceptTextureType(TType&);
diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp
index ff2c3014b460ae5fe1a1aa9f6ca73ec1ca3c1634..4957767767c43967abaecec3611614efb89065b7 100755
--- a/hlsl/hlslParseHelper.cpp
+++ b/hlsl/hlslParseHelper.cpp
@@ -758,6 +758,13 @@ TIntermTyped* HlslParseContext::handleDotDereference(const TSourceLoc& loc, TInt
                 return intermediate.addMethod(base, TType(sampler.type, EvqTemporary, vecSize), &field, loc);
             }
         }
+    } else if (field == "Append" ||
+               field == "RestartStrip") {
+        // These methods only valid on stage in variables
+        // TODO: ... which are stream out types, if there's any way to test that here.
+        if (base->getType().getQualifier().storage == EvqVaryingOut) {
+            return intermediate.addMethod(base, TType(EbtVoid), &field, loc);
+        }
     }
 
     // It's not .length() if we get to here.
@@ -1137,12 +1144,19 @@ TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& l
     postMainReturn = false;
 
     // Handle function attributes
-    const TIntermAggregate* numThreadliterals = attributes[EatNumthreads];
-    if (numThreadliterals != nullptr && inEntryPoint) {
-        const TIntermSequence& sequence = numThreadliterals->getSequence();
+    if (inEntryPoint) {
+        const TIntermAggregate* numThreads = attributes[EatNumThreads];
+        if (numThreads != nullptr) {
+            const TIntermSequence& sequence = numThreads->getSequence();
  
-        for (int lid = 0; lid < int(sequence.size()); ++lid)
-            intermediate.setLocalSize(lid, sequence[lid]->getAsConstantUnion()->getConstArray()[0].getIConst());
+            for (int lid = 0; lid < int(sequence.size()); ++lid)
+                intermediate.setLocalSize(lid, sequence[lid]->getAsConstantUnion()->getConstArray()[0].getIConst());
+        }
+
+        const TIntermAggregate* maxVertexCount = attributes[EatMaxVertexCount];
+        if (maxVertexCount != nullptr) {
+            intermediate.setVertices(maxVertexCount->getSequence()[0]->getAsConstantUnion()->getConstArray()[0].getIConst());
+        }
     }
 
     return paramNodes;
@@ -2063,6 +2077,55 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
     }
 }
 
+//
+// Decompose geometry shader methods
+//
+void HlslParseContext::decomposeGeometryMethods(const TSourceLoc& loc, TIntermTyped*& node, TIntermNode* arguments)
+{
+    if (!node || !node->getAsOperator())
+        return;
+
+    const TOperator op  = node->getAsOperator()->getOp();
+    const TIntermAggregate* argAggregate = arguments ? arguments->getAsAggregate() : nullptr;
+
+    switch (op) {
+    case EOpMethodAppend:
+        if (argAggregate) {
+            TIntermAggregate* sequence = nullptr;
+            TIntermAggregate* emit = new TIntermAggregate(EOpEmitVertex);
+
+            emit->setLoc(loc);
+            emit->setType(TType(EbtVoid));
+
+            sequence = intermediate.growAggregate(sequence,
+                                                  intermediate.addAssign(EOpAssign, 
+                                                                         argAggregate->getSequence()[0]->getAsTyped(),
+                                                                         argAggregate->getSequence()[1]->getAsTyped(), loc),
+                                                  loc);
+
+            sequence = intermediate.growAggregate(sequence, emit);
+
+            sequence->setOperator(EOpSequence);
+            sequence->setLoc(loc);
+            sequence->setType(TType(EbtVoid));
+            node = sequence;
+        }
+        break;
+
+    case EOpMethodRestartStrip:
+        {
+            TIntermAggregate* cut = new TIntermAggregate(EOpEndPrimitive);
+            cut->setLoc(loc);
+            cut->setType(TType(EbtVoid));
+            node = cut;
+        }
+        break;
+
+    default:
+        break; // most pass through unchanged
+    }
+}
+
 //
 // Optionally decompose intrinsics to AST opcodes.
 //
@@ -2546,8 +2609,9 @@ TIntermTyped* HlslParseContext::handleFunctionCall(const TSourceLoc& loc, TFunct
                 result = addOutputArgumentConversions(*fnCandidate, *result->getAsAggregate());
             }
 
-            decomposeIntrinsic(loc, result, arguments);      // HLSL->AST intrinsic decompositions
-            decomposeSampleMethods(loc, result, arguments);  // HLSL->AST sample method decompositions
+            decomposeIntrinsic(loc, result, arguments);       // HLSL->AST intrinsic decompositions
+            decomposeSampleMethods(loc, result, arguments);   // HLSL->AST sample method decompositions
+            decomposeGeometryMethods(loc, result, arguments); // HLSL->AST geometry method decompositions
         }
     }
 
@@ -4295,6 +4359,14 @@ const TFunction* HlslParseContext::findFunction(const TSourceLoc& loc, const TFu
     TVector<const TFunction*> candidateList;
     symbolTable.findFunctionNameList(call.getMangledName(), candidateList, builtIn);
     
+    // These builtin ops can accept any type, so we bypass the argument selection
+    if (candidateList.size() == 1 && builtIn &&
+        (candidateList[0]->getBuiltInOp() == EOpMethodAppend ||
+         candidateList[0]->getBuiltInOp() == EOpMethodRestartStrip)) {
+
+        return candidateList[0];
+    }
+
     // can 'from' convert to 'to'?
     const auto convertible = [this](const TType& from, const TType& to) -> bool {
         if (from == to)
@@ -5202,6 +5274,53 @@ void HlslParseContext::addQualifierToExisting(const TSourceLoc& loc, TQualifier
         addQualifierToExisting(loc, qualifier, *identifiers[i]);
 }
 
+//
+// Update the intermediate for the given input geometry
+//
+bool HlslParseContext::handleInputGeometry(const TSourceLoc& loc, const TLayoutGeometry& geometry)
+{
+    switch (geometry) {
+    case ElgPoints:             // fall through
+    case ElgLines:              // ...
+    case ElgTriangles:          // ...
+    case ElgLinesAdjacency:     // ...
+    case ElgTrianglesAdjacency: // ...
+        if (! intermediate.setInputPrimitive(geometry)) {
+            error(loc, "input primitive geometry redefinition", TQualifier::getGeometryString(geometry), "");
+            return false;
+        }
+        break;
+
+    default:
+        error(loc, "cannot apply to 'in'", TQualifier::getGeometryString(geometry), "");
+        return false;
+    }
+
+    return true;
+}
+
+//
+// Update the intermediate for the given output geometry
+//
+bool HlslParseContext::handleOutputGeometry(const TSourceLoc& loc, const TLayoutGeometry& geometry)
+{
+    switch (geometry) {
+    case ElgPoints:
+    case ElgLineStrip:
+    case ElgTriangleStrip:
+        if (! intermediate.setOutputPrimitive(geometry)) {
+            error(loc, "output primitive geometry redefinition", TQualifier::getGeometryString(geometry), "");
+            return false;
+        }
+        break;
+    default:
+        error(loc, "cannot apply to 'out'", TQualifier::getGeometryString(geometry), "");
+        return false;
+    }
+
+    return true;
+}
+
 //
 // Updating default qualifier for the case of a declaration with just a qualifier,
 // no type, block, or identifier.
@@ -5231,16 +5350,7 @@ void HlslParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc,
                 error(loc, "cannot apply to input", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), "");
             }
         } else if (publicType.qualifier.storage == EvqVaryingOut) {
-            switch (publicType.shaderQualifiers.geometry) {
-            case ElgPoints:
-            case ElgLineStrip:
-            case ElgTriangleStrip:
-                if (! intermediate.setOutputPrimitive(publicType.shaderQualifiers.geometry))
-                    error(loc, "cannot change previously set output primitive", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), "");
-                break;
-            default:
-                error(loc, "cannot apply to 'out'", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), "");
-            }
+            handleOutputGeometry(loc, publicType.shaderQualifiers.geometry);
         } else
             error(loc, "cannot apply to:", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), GetStorageQualifierString(publicType.qualifier.storage));
     }
diff --git a/hlsl/hlslParseHelper.h b/hlsl/hlslParseHelper.h
index 9a7285f981bda8ff9a256045c31327104dbdbb77..3862c10f0c2666e6c8754b2e4d2406d6680083cc 100755
--- a/hlsl/hlslParseHelper.h
+++ b/hlsl/hlslParseHelper.h
@@ -81,6 +81,7 @@ public:
     TIntermTyped* handleFunctionCall(const TSourceLoc&, TFunction*, TIntermNode*);
     void decomposeIntrinsic(const TSourceLoc&, TIntermTyped*& node, TIntermNode* arguments);
     void decomposeSampleMethods(const TSourceLoc&, TIntermTyped*& node, TIntermNode* arguments);
+    void decomposeGeometryMethods(const TSourceLoc&, TIntermTyped*& node, TIntermNode* arguments);
     TIntermTyped* handleLengthMethod(const TSourceLoc&, TFunction*, TIntermNode*);
     void addInputArgumentConversions(const TFunction&, TIntermNode*&) const;
     TIntermTyped* addOutputArgumentConversions(const TFunction&, TIntermAggregate&);
@@ -160,6 +161,9 @@ public:
 
     TLayoutFormat getLayoutFromTxType(const TSourceLoc&, const TType&);
 
+    bool handleOutputGeometry(const TSourceLoc&, const TLayoutGeometry& geometry);
+    bool handleInputGeometry(const TSourceLoc&, const TLayoutGeometry& geometry);
+
 protected:
     void inheritGlobalDefaults(TQualifier& dst) const;
     TVariable* makeInternalVariable(const char* name, const TType&) const;
diff --git a/hlsl/hlslParseables.cpp b/hlsl/hlslParseables.cpp
index 7ab159dc04892b186d3a203657d6158718288500..f8fed0d8e9aa4736484e2948c3177a778b0a38da 100755
--- a/hlsl/hlslParseables.cpp
+++ b/hlsl/hlslParseables.cpp
@@ -502,6 +502,7 @@ void TBuiltInParseablesHlsl::initialize(int /*version*/, EProfile /*profile*/, c
     static const EShLanguageMask EShLangCS     = EShLangAll;
     static const EShLanguageMask EShLangPS     = EShLangAll;
     static const EShLanguageMask EShLangHS     = EShLangAll;
+    static const EShLanguageMask EShLangGS     = EShLangAll;
 
     // This structure encodes the prototype information for each HLSL intrinsic.
     // Because explicit enumeration would be cumbersome, it's procedurally generated.
@@ -831,6 +832,10 @@ void TBuiltInParseablesHlsl::initialize(int /*version*/, EProfile /*profile*/, c
         { "GatherCmpAlpha",  /* O-4 */        "V4",    nullptr,   "%@,S,V,S,V,,,",  "FIU,s,F,,I,,,",  EShLangAll },
         { "GatherCmpAlpha",  /* O-4, status */"V4",    nullptr,   "%@,S,V,S,V,,,,S","FIU,s,F,,I,,,,U",EShLangAll },
 
+        // geometry methods
+        { "Append",                           "-",     "-",       "-",              "-",              EShLangGS  },
+        { "RestartStrip",                     "-",     "-",       "-",              "-",              EShLangGS  },
+
         // Mark end of list, since we want to avoid a range-based for, as some compilers don't handle it yet.
         { nullptr,                            nullptr, nullptr,   nullptr,      nullptr,  0 },
     };
@@ -1140,6 +1145,10 @@ void TBuiltInParseablesHlsl::identifyBuiltIns(int /*version*/, EProfile /*profil
     symbolTable.relateToOperator("GatherCmpGreen",              EOpMethodGatherCmpGreen);
     symbolTable.relateToOperator("GatherCmpBlue",               EOpMethodGatherCmpBlue);
     symbolTable.relateToOperator("GatherCmpAlpha",              EOpMethodGatherCmpAlpha);
+
+    // GS methods
+    symbolTable.relateToOperator("Append",                      EOpMethodAppend);
+    symbolTable.relateToOperator("RestartStrip",                EOpMethodRestartStrip);
 }
 
 //
diff --git a/hlsl/hlslScanContext.cpp b/hlsl/hlslScanContext.cpp
index e7cd1fcf11658904a8e4809e0599644fbf1d6953..2c45b3ff1d848b0068bb40d6bee5e0adc8dd70c9 100755
--- a/hlsl/hlslScanContext.cpp
+++ b/hlsl/hlslScanContext.cpp
@@ -119,6 +119,16 @@ void HlslScanContext::fillInKeywordMap()
     (*KeywordMap)["inout"] =                   EHTokInOut;
     (*KeywordMap)["layout"] =                  EHTokLayout;
 
+    (*KeywordMap)["point"] =                   EHTokPoint;
+    (*KeywordMap)["line"] =                    EHTokLine;
+    (*KeywordMap)["triangle"] =                EHTokTriangle;
+    (*KeywordMap)["lineadj"] =                 EHTokLineAdj;
+    (*KeywordMap)["triangleadj"] =             EHTokTriangleAdj;
+
+    (*KeywordMap)["PointStream"] =             EHTokPointStream;
+    (*KeywordMap)["LineStream"] =              EHTokLineStream;
+    (*KeywordMap)["TriangleStream"] =          EHTokTriangleStream;
+
     (*KeywordMap)["Buffer"] =                  EHTokBuffer;
     (*KeywordMap)["vector"] =                  EHTokVector;
     (*KeywordMap)["matrix"] =                  EHTokMatrix;
@@ -496,7 +506,20 @@ EHlslTokenClass HlslScanContext::tokenizeIdentifier()
     case EHTokLayout:
         return keyword;
 
-    // template types
+    // primitive types
+    case EHTokPoint:
+    case EHTokLine:
+    case EHTokTriangle:
+    case EHTokLineAdj:
+    case EHTokTriangleAdj:
+        return keyword;
+
+    // stream out types
+    case EHTokPointStream:
+    case EHTokLineStream:
+    case EHTokTriangleStream:
+        return keyword;
+
     case EHTokBuffer:
     case EHTokVector:
     case EHTokMatrix:
diff --git a/hlsl/hlslTokens.h b/hlsl/hlslTokens.h
index d634c8eeb745e343c74cfca0613798d18dbf80b5..6902070cbe3e9e455c8c7ddc893ea3086e74e301 100755
--- a/hlsl/hlslTokens.h
+++ b/hlsl/hlslTokens.h
@@ -66,6 +66,18 @@ enum EHlslTokenClass {
     EHTokInOut,
     EHTokLayout,
 
+    // primitive types
+    EHTokPoint,
+    EHTokLine,
+    EHTokTriangle,
+    EHTokLineAdj,
+    EHTokTriangleAdj,
+
+    // stream out types
+    EHTokPointStream,
+    EHTokLineStream,
+    EHTokTriangleStream,
+
     // template types
     EHTokBuffer,
     EHTokVector,