diff --git a/Test/300layout.frag b/Test/300layout.frag
new file mode 100644
index 0000000000000000000000000000000000000000..618582d3cff7b692ebeb5ac020883a3ee6cb260e
--- /dev/null
+++ b/Test/300layout.frag
@@ -0,0 +1,29 @@
+#version 300 es
+
+in vec4 pos;
+in vec4 color;
+
+layout(location = 7) out vec4 c;
+layout(location = 3) out vec4 p;
+
+//layout(std140) uniform Transform { // layout of this block is std140
+//    mat4 M1; // row_major
+//    layout(column_major) mat4 M2; // column major
+//    mat3 N1; // row_major
+//};
+//
+//uniform T2 { // layout of this block is shared
+//...
+//};
+//
+//layout(column_major) uniform T3 { // shared and column_major
+//    mat4 M3; // column_major
+//    layout(row_major) mat4 m4; // row major
+//    mat3 N2; // column_major
+//};
+
+void main()
+{
+    c = color;
+    p = pos;
+}
diff --git a/Test/300layout.vert b/Test/300layout.vert
new file mode 100644
index 0000000000000000000000000000000000000000..fd177ddb24bda939bdcf1d5e3cca72a0cabbb580
--- /dev/null
+++ b/Test/300layout.vert
@@ -0,0 +1,30 @@
+#version 300 es
+
+layout(location = 7) in vec4 c;
+layout(LocatioN = 3) in vec4 p;
+out vec4 pos;
+out vec4 color;
+
+layout(shared, column_major, row_major) uniform mat4 m4; // default is now shared and row_major
+
+//layout(std140) uniform Transform { // layout of this block is std140
+//    mat4 M1; // row_major
+//    layout(column_major) mat4 M2; // column major
+//    mat3 N1; // row_major
+//};
+//
+//uniform T2 { // layout of this block is shared
+//...
+//};
+//
+//layout(column_major) uniform T3 { // shared and column_major
+//    mat4 M3; // column_major
+//    layout(row_major) mat4 m4; // row major
+//    mat3 N2; // column_major
+//};
+
+void main()
+{
+    pos = p * m4;
+    color = c;
+}
diff --git a/Test/testlist b/Test/testlist
index 7ae5e7bd49f2704c88fa26899b697bdfd6831064..36c3bc9f537a66ba7b5d347abdbe2b31867a8220 100644
--- a/Test/testlist
+++ b/Test/testlist
@@ -24,6 +24,8 @@ comment.frag
 300.vert
 300.frag
 300BuiltIns.frag
+300layout.vert
+300layout.frag
 330.frag
 330comp.frag
 constErrors.frag
diff --git a/glslang/Include/BaseTypes.h b/glslang/Include/BaseTypes.h
index 613a0ba290c8b96db17862fd76049bd0607945e6..367ce36e7b519c09b8ce00ccb3ac084954716cdd 100644
--- a/glslang/Include/BaseTypes.h
+++ b/glslang/Include/BaseTypes.h
@@ -64,7 +64,8 @@ enum TStorageQualifier {
     EvqConst,         // User defined constants and non-output parameters in functions
     EvqVaryingIn,     // pipeline input, read only
     EvqVaryingOut,    // pipeline ouput, read/write
-    EvqUniform,       // Readonly, vertex and fragment
+    EvqUniform,       // read only, shader with app
+    EVqBuffer,        // read only, shader with app
 
     // parameters
     EvqIn,
@@ -102,8 +103,8 @@ __inline const char* getStorageQualifierString(TStorageQualifier q)
     case EvqGlobal:         return "global";         break;
     case EvqConst:          return "const";          break;
     case EvqConstReadOnly:  return "const (read only)"; break;
-    case EvqVaryingIn:      return "shader in";      break;
-    case EvqVaryingOut:     return "shader out";     break;
+    case EvqVaryingIn:      return "in";             break;
+    case EvqVaryingOut:     return "out";            break;
     case EvqUniform:        return "uniform";        break;
     case EvqIn:             return "in";             break;
     case EvqOut:            return "out";            break;
@@ -116,7 +117,7 @@ __inline const char* getStorageQualifierString(TStorageQualifier q)
     case EvqFace:           return "gl_FrontFacing"; break;
     case EvqFragCoord:      return "gl_FragCoord";   break;
     case EvqPointCoord:     return "gl_PointCoord";  break;
-    case EvqFragColor:      return "fragment out";   break;
+    case EvqFragColor:      return "fragColor";      break;
     case EvqFragDepth:      return "gl_FragDepth";   break;
     default:                return "unknown qualifier";
     }
diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h
index e1214ced6108e839f9aef8d19c73f37f197eaf80..b13f331489ed5d6a53ea195ad0123c0514be8a9c 100644
--- a/glslang/Include/Types.h
+++ b/glslang/Include/Types.h
@@ -171,7 +171,8 @@ inline TArraySizes NewPoolTArraySizes()
 }
 
 //
-// TPublicType is a workaround for a problem with the yacc stack,  It can't have
+// TPublicType (coming up after some dependent declarations)
+// is a workaround for a problem with the yacc stack,  It can't have
 // types that it thinks have non-trivial constructors.  It should
 // just be used while recognizing the grammar, not anything else.  Pointers
 // could be used, but also trying to avoid lots of memory management overhead.
@@ -180,13 +181,26 @@ inline TArraySizes NewPoolTArraySizes()
 // match up or are named the same or anything like that.
 //
 
+enum TLayoutPacking {
+    ElpNone,
+    ElpShared,      // default, but different than saying nothing
+    ElpStd140,
+    ElpStd430,
+    ElpPacked       // see bitfield width below
+};
+
+enum TLayoutMatrix {
+    ElmNone,
+    ElmRowMajor,
+    ElmColumnMajor  // default, but different than saying nothing
+};  // see bitfield width below
+
 class TQualifier {
 public:
     void clear()
     {
         storage   = EvqTemporary;
         precision = EpqNone;
-        buffer    = false;
         invariant = false;
         centroid  = false;
         smooth    = false;
@@ -200,10 +214,10 @@ public:
         restrict  = false;
         readonly  = false;
         writeonly = false;
+        clearLayout();
     }
-	TStorageQualifier storage     : 7;
+	TStorageQualifier   storage   : 6;
     TPrecisionQualifier precision : 3;
-    bool buffer    : 1;
     bool invariant : 1;
     bool centroid  : 1;
     bool smooth    : 1;
@@ -217,6 +231,7 @@ public:
     bool restrict  : 1;
     bool readonly  : 1;
     bool writeonly : 1;
+
     bool isMemory()
     {
         return coherent || volatil || restrict || readonly || writeonly;
@@ -229,6 +244,46 @@ public:
     {
         return centroid || patch || sample;
     }
+
+    // Implementing an embedded layout-qualifier class here, since C++ can't have a real class bitfield
+    void clearLayout()
+    {
+        layoutMatrix = ElmNone;
+        layoutPacking = ElpNone;
+        layoutSlotLocation = layoutLocationEnd;
+    }
+    bool hasLayout() const
+    {
+        return layoutMatrix != ElmNone ||
+               layoutPacking != ElpNone ||
+               layoutSlotLocation != layoutLocationEnd;
+    }
+    TLayoutMatrix  layoutMatrix       : 3;
+    TLayoutPacking layoutPacking      : 4;
+    unsigned int   layoutSlotLocation : 7;  // ins/outs should have small numbers, buffer offsets could be large
+    static const unsigned int layoutLocationEnd = 0x3F;
+    bool hasLocation() const
+    {
+        return layoutSlotLocation != layoutLocationEnd;
+    }
+    static const char* getLayoutPackingString(TLayoutPacking packing)
+    {
+        switch (packing) {
+        case ElpPacked:   return "packed";
+        case ElpShared:   return "shared";
+        case ElpStd140:   return "std140";
+        case ElpStd430:   return "std430";
+        default:          return "none";
+        }
+    }
+    static const char* getLayoutMatrixString(TLayoutMatrix m)
+    {
+        switch (m) {
+        case ElmColumnMajor: return "column_major";
+        case ElmRowMajor:    return "row_major";
+        default:             return "none";
+        }
+    }
 };
 
 class TPublicType {
@@ -479,8 +534,17 @@ public:
         char *p = &buf[0];
 	    char *end = &buf[maxSize];
 
-        if (qualifier.buffer)
-            p += snprintf(p, end - p, "buffer ");
+        if (qualifier.hasLayout()) {
+            p += snprintf(p, end - p, "layout(");
+            if (qualifier.hasLocation())
+                p += snprintf(p, end - p, "location=%d ", qualifier.layoutSlotLocation);
+            if (qualifier.layoutMatrix != ElmNone)
+                p += snprintf(p, end - p, "%s ", TQualifier::getLayoutMatrixString(qualifier.layoutMatrix));
+            if (qualifier.layoutPacking != ElpNone)
+                p += snprintf(p, end - p, "%s ", TQualifier::getLayoutPackingString(qualifier.layoutPacking));
+            p += snprintf(p, end - p, ") ");
+        }
+
         if (qualifier.invariant)
             p += snprintf(p, end - p, "invariant ");
         if (qualifier.centroid)
diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp
index 2b35ae31667641c8d93c53214f5b9307affb1a6e..363af6016525fcf28b5dfc5a713adaae4ff97192 100644
--- a/glslang/MachineIndependent/ParseHelper.cpp
+++ b/glslang/MachineIndependent/ParseHelper.cpp
@@ -38,6 +38,7 @@
 #include "Include/InitializeParseContext.h"
 #include "osinclude.h"
 #include <stdarg.h>
+#include <algorithm>
 
 TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, int v, EProfile p, EShLanguage L, TInfoSink& is,                             
                              bool fc, EShMessages m) : 
@@ -706,7 +707,7 @@ bool TParseContext::globalQualifierFixAndErrorCheck(int line, TQualifier& qualif
     }
 
     if (language == EShLangVertex && qualifier.storage == EvqVaryingIn && 
-        (qualifier.isAuxillary() || qualifier.isInterpolation() || qualifier.isMemory() || qualifier.buffer || qualifier.invariant)) {
+        (qualifier.isAuxillary() || qualifier.isInterpolation() || qualifier.isMemory() || qualifier.invariant)) {
         error(line, "vertex input cannot be further qualified", "", "");
 
         return true;
@@ -748,9 +749,11 @@ bool TParseContext::mergeQualifiersErrorCheck(int line, TPublicType& left, const
         bad = true;
     }
 
+    // Layout qualifiers
+    mergeLayoutQualifiers(line, left, right);
+
     // other qualifiers
     #define MERGE_SINGLETON(field) bad |= left.qualifier.field && right.qualifier.field; left.qualifier.field |= right.qualifier.field;
-    MERGE_SINGLETON(buffer);
     MERGE_SINGLETON(invariant);
     MERGE_SINGLETON(centroid);
     MERGE_SINGLETON(smooth);
@@ -1086,6 +1089,62 @@ bool TParseContext::paramErrorCheck(int line, TStorageQualifier qualifier, TType
     }
 }
 
+//
+// Layout qualifier stuff.
+//
+
+// Put the id's layout qualification into the public type.
+void TParseContext::setLayoutQualifier(int line, TPublicType& publicType, TString& id)
+{
+    std::transform(id.begin(), id.end(), id.begin(), ::tolower);
+    if (id == TQualifier::getLayoutMatrixString(ElmColumnMajor))
+        publicType.qualifier.layoutMatrix = ElmColumnMajor;
+    else if (id == TQualifier::getLayoutMatrixString(ElmRowMajor))
+        publicType.qualifier.layoutMatrix = ElmRowMajor;
+    else if (id == TQualifier::getLayoutPackingString(ElpPacked))
+        publicType.qualifier.layoutPacking = ElpPacked;
+    else if (id == TQualifier::getLayoutPackingString(ElpShared))
+        publicType.qualifier.layoutPacking = ElpShared;
+    else if (id == TQualifier::getLayoutPackingString(ElpStd140))
+        publicType.qualifier.layoutPacking = ElpStd140;
+    else if (id == TQualifier::getLayoutPackingString(ElpStd430))
+        publicType.qualifier.layoutPacking = ElpStd430;
+    else if (id == "location")
+        error(line, "requires an integer assignment (e.g., location = 4)", "location", "");
+    else if (id == "binding")
+        error(line, "requires an integer assignment (e.g., binding = 4)", "binding", "");
+    else
+        error(line, "unrecognized layout identifier", id.c_str(), "");
+}
+
+// Put the id's layout qualifier value into the public type.
+void TParseContext::setLayoutQualifier(int line, TPublicType& publicType, TString& id, int value)
+{
+    std::transform(id.begin(), id.end(), id.begin(), ::tolower);
+    if (id == "location") {
+        if ((unsigned int)value >= TQualifier::layoutLocationEnd)
+            error(line, "value is too large", id.c_str(), "");
+        else
+            publicType.qualifier.layoutSlotLocation = value;
+    } else if (id == "binding")
+        error(line, "not supported", "binding", "");
+    else
+        error(line, "there is no such layout identifier taking an assigned value", id.c_str(), "");
+}
+
+// Merge any layout qualifier information from src into dst, leaving everything else in dst alone
+void TParseContext::mergeLayoutQualifiers(int line, TPublicType& dst, const TPublicType& src)
+{
+    if (src.qualifier.layoutMatrix != ElmNone)
+        dst.qualifier.layoutMatrix = src.qualifier.layoutMatrix;
+
+    if (src.qualifier.layoutPacking != ElpNone)
+        dst.qualifier.layoutPacking = src.qualifier.layoutPacking;
+
+    if (src.qualifier.hasLocation())
+        dst.qualifier.layoutSlotLocation = src.qualifier.layoutSlotLocation;
+}
+
 /////////////////////////////////////////////////////////////////////////////////
 //
 // Non-Errors.
diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h
index a5de17ac3c2fb76644e76a4e29fab1b4321ad3f2..13e334513d3537a9037935f09c0d9416f51ce0b5 100644
--- a/glslang/MachineIndependent/ParseHelper.h
+++ b/glslang/MachineIndependent/ParseHelper.h
@@ -129,6 +129,11 @@ struct TParseContext {
     bool nonInitConstErrorCheck(int line, TString& identifier, TPublicType& type);
     bool nonInitErrorCheck(int line, TString& identifier, TPublicType& type);
     bool paramErrorCheck(int line, TStorageQualifier qualifier, TType* type);
+
+    void setLayoutQualifier(int line, TPublicType&, TString&);
+    void setLayoutQualifier(int line, TPublicType&, TString&, int);
+    void mergeLayoutQualifiers(int line, TPublicType& dest, const TPublicType& src);
+
     const TFunction* findFunction(int line, TFunction* pfnCall, bool *builtIn = 0);
     bool executeInitializer(TSourceLoc line, TString& identifier, TPublicType& pType,
                             TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable = 0);
diff --git a/glslang/MachineIndependent/glslang.y b/glslang/MachineIndependent/glslang.y
index 67aa3d031241403e33c34aa99eb624e6f88bd7d0..6c84725ff882b29f7886d46f6a4917187864a50a 100644
--- a/glslang/MachineIndependent/glslang.y
+++ b/glslang/MachineIndependent/glslang.y
@@ -201,7 +201,7 @@ extern void yyerror(const char*);
 
 %type <interm> array_specifier
 %type <interm.type> precise_qualifier invariant_qualifier interpolation_qualifier storage_qualifier precision_qualifier
-%type <interm.type> layout_qualifier layout_qualifier_id_list
+%type <interm.type> layout_qualifier layout_qualifier_id_list layout_qualifier_id
 
 %type <interm.type> type_qualifier fully_specified_type type_specifier
 %type <interm.type> single_type_qualifier
@@ -1622,22 +1622,31 @@ interpolation_qualifier
 
 layout_qualifier
     : LAYOUT LEFT_PAREN layout_qualifier_id_list RIGHT_PAREN {
-        $$.init($1.line);
+        $$ = $3;
     }
     ;
 
 layout_qualifier_id_list
     : layout_qualifier_id {
+        $$ = $1;
     }
     | layout_qualifier_id_list COMMA layout_qualifier_id {
+        $$ = $1;
+        parseContext.mergeLayoutQualifiers($2.line, $$, $3);
     }
 
 layout_qualifier_id
     : IDENTIFIER {
+        $$.init($1.line);
+        parseContext.setLayoutQualifier($1.line, $$, *$1.string);
     }
     | IDENTIFIER EQUAL INTCONSTANT {
+        $$.init($1.line);
+        parseContext.setLayoutQualifier($1.line, $$, *$1.string, $3.i);
     }
-    | SHARED {
+    | SHARED { // because "shared" is both an identifier and a keyword
+        $$.init($1.line);
+        parseContext.setLayoutQualifier($1.line, $$, TString("shared"));
     }
     ;
 
@@ -1766,8 +1775,7 @@ storage_qualifier
         if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "buffer"))
             parseContext.recover();
         $$.init($1.line);
-        $$.qualifier.storage = EvqUniform;
-        $$.qualifier.buffer = true;
+        $$.qualifier.storage = EvqUniform; // TODO: functionality: implement BUFFER
     }
     | SHARED {
         $$.init($1.line);