Turn on basic support for shader storage buffer objects, but not yet the entire extension.


git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@27699 e7fa87d3-cd2b-0410-9028-fcbf551c1848
diff --git a/Test/430.comp b/Test/430.comp
index 13a812d..f022f8f 100644
--- a/Test/430.comp
+++ b/Test/430.comp
@@ -12,6 +12,18 @@
                 + gl_MaxComputeAtomicCounters

                 + gl_MaxComputeAtomicCounterBuffers;

 

+buffer ShaderStorageBlock

+{

+    int value;

+    float values[];

+};

+

+buffer InvalidShaderStorageBlock

+{

+    float values[];  // ERROR

+    int value;

+} invalid;

+

 void main()

 {

     barrier();

@@ -21,6 +33,7 @@
     memoryBarrierShared();

     memoryBarrierImage();

     groupMemoryBarrier();

+    value = int(values[gl_LocalInvocationIndex]);

 }

 

 layout(location = 2) in vec3 v3;      // ERROR

@@ -36,3 +49,15 @@
 int arrX[gl_WorkGroupSize.x];

 int arrY[gl_WorkGroupSize.y];

 int arrZ[gl_WorkGroupSize.z];

+

+readonly buffer roblock

+{

+    int value;

+    float values[];

+} ro;

+

+void foo()

+{

+    ro.values[2] = 4.7;        // ERROR, readonly

+    ro.values.length();

+}

diff --git a/Test/baseResults/300layout.vert.out b/Test/baseResults/300layout.vert.out
index 52de07b..b5b1e26 100644
--- a/Test/baseResults/300layout.vert.out
+++ b/Test/baseResults/300layout.vert.out
@@ -5,7 +5,7 @@
 ERROR: 0:8: 'location' : overlapping use of location 10

 ERROR: 0:12: 'layout' : cannot specify matrix layout on a variable declaration 

 ERROR: 0:12: 'layout' : cannot specify packing on a variable declaration 

-ERROR: 0:19: 'badf' : member of uniform block cannot have an auxiliary or interpolation qualifier 

+ERROR: 0:19: 'badf' : member of uniform or buffer block cannot have an auxiliary or interpolation qualifier 

 ERROR: 0:20: 'badg' : member storage qualifier cannot contradict block storage qualifier 

 ERROR: 0:21: 'bad1' : member of block cannot have a packing layout qualifier 

 ERROR: 0:22: 'bad2' : member of block cannot have a packing layout qualifier 

diff --git a/Test/baseResults/420.vert.out b/Test/baseResults/420.vert.out
index 94f849b..2d8bf8b 100644
--- a/Test/baseResults/420.vert.out
+++ b/Test/baseResults/420.vert.out
@@ -38,8 +38,8 @@
 ERROR: 0:114: 'imageAtomicMin' : only supported on image with format r32i or r32ui 

 ERROR: 0:115: 'imageAtomicMax' : no matching overloaded function found 

 ERROR: 0:119: 'writeonly' : argument cannot drop memory qualifier when passed to formal parameter 

-ERROR: 0:122: '' : memory qualifiers can only be used on image types 

-ERROR: 0:123: '' : memory qualifiers can only be used on image types 

+ERROR: 0:122: '' : memory qualifiers cannot be used on this type 

+ERROR: 0:123: '' : memory qualifiers cannot be used on this type 

 ERROR: 0:135: 'restrict' : argument cannot drop memory qualifier when passed to formal parameter 

 ERROR: 0:139: 'rg8i' : does not apply to unsigned integer images 

 ERROR: 0:140: 'rgba32i' : does not apply to floating point images 

diff --git a/Test/baseResults/430.comp.out b/Test/baseResults/430.comp.out
index 4e3f8fd..b1fed46 100644
--- a/Test/baseResults/430.comp.out
+++ b/Test/baseResults/430.comp.out
@@ -2,32 +2,64 @@
 Warning, version 430 is not yet complete; most version-specific features are present, but some are missing.

 ERROR: 0:4: 'local_size' : cannot change previously set size 

 ERROR: 0:5: 'local_size' : too large; see gl_MaxComputeWorkGroupSize 

-ERROR: 0:26: 'in' : global storage input qualifier cannot be used in a compute shader 

-ERROR: 0:26: 'location qualifier on input' : not supported in this stage: compute

-ERROR: 0:27: 'in' : global storage input qualifier cannot be used in a compute shader 

-ERROR: 0:28: 'out' : global storage output qualifier cannot be used in a compute shader 

-ERROR: 0:31: 'shared' : cannot apply layout qualifiers to a shared variable 

-ERROR: 0:31: 'location' : can only appy to uniform, buffer, in, or out storage qualifiers 

-ERROR: 0:32: 'shared' :  cannot initialize this type of qualifier  

-ERROR: 0:34: 'local_size' : can only apply to 'in' 

-ERROR: 0:34: 'local_size' : can only apply to 'in' 

-ERROR: 0:34: 'local_size' : can only apply to 'in' 

-ERROR: 12 compilation errors.  No code generated.

+ERROR: 0:23: 'values' : only the last member of a buffer block can be run-time sized 

+ERROR: 0:39: 'in' : global storage input qualifier cannot be used in a compute shader 

+ERROR: 0:39: 'location qualifier on input' : not supported in this stage: compute

+ERROR: 0:40: 'in' : global storage input qualifier cannot be used in a compute shader 

+ERROR: 0:41: 'out' : global storage output qualifier cannot be used in a compute shader 

+ERROR: 0:44: 'shared' : cannot apply layout qualifiers to a shared variable 

+ERROR: 0:44: 'location' : can only appy to uniform, buffer, in, or out storage qualifiers 

+ERROR: 0:45: 'shared' :  cannot initialize this type of qualifier  

+ERROR: 0:47: 'local_size' : can only apply to 'in' 

+ERROR: 0:47: 'local_size' : can only apply to 'in' 

+ERROR: 0:47: 'local_size' : can only apply to 'in' 

+ERROR: 0:61: 'assign' :  l-value required "ro" (can't modify a readonly buffer)

+ERROR: 14 compilation errors.  No code generated.

 

 

 Shader version: 430

 local_size = (2, 1, 4096)

 ERROR: node is still EOpNull!

-0:15  Function Definition: main( (void)

-0:15    Function Parameters: 

-0:17    Sequence

-0:17      Barrier (void)

-0:18      MemoryBarrier (void)

-0:19      MemoryBarrierAtomicCounter (void)

-0:20      MemoryBarrierBuffer (void)

-0:21      MemoryBarrierShared (void)

-0:22      MemoryBarrierImage (void)

-0:23      GroupMemoryBarrier (void)

+0:27  Function Definition: main( (void)

+0:27    Function Parameters: 

+0:29    Sequence

+0:29      Barrier (void)

+0:30      MemoryBarrier (void)

+0:31      MemoryBarrierAtomicCounter (void)

+0:32      MemoryBarrierBuffer (void)

+0:33      MemoryBarrierShared (void)

+0:34      MemoryBarrierImage (void)

+0:35      GroupMemoryBarrier (void)

+0:36      move second child to first child (int)

+0:36        value: direct index for structure (layout(column_major shared ) buffer int)

+0:36          'anon@0' (layout(column_major shared ) buffer block{layout(column_major shared ) buffer int value, layout(column_major shared ) buffer implicitly-sized array of float values})

+0:36          Constant:

+0:36            0 (const uint)

+0:36        Convert float to int (int)

+0:36          indirect index (layout(column_major shared ) float)

+0:36            values: direct index for structure (layout(column_major shared ) buffer implicitly-sized array of float)

+0:36              'anon@0' (layout(column_major shared ) buffer block{layout(column_major shared ) buffer int value, layout(column_major shared ) buffer implicitly-sized array of float values})

+0:36              Constant:

+0:36                1 (const uint)

+0:36            'gl_LocalInvocationIndex' (in uint)

+0:59  Function Definition: foo( (void)

+0:59    Function Parameters: 

+0:61    Sequence

+0:61      move second child to first child (float)

+0:61        direct index (layout(column_major shared ) float)

+0:61          values: direct index for structure (layout(column_major shared ) buffer implicitly-sized array of float)

+0:61            'ro' (layout(column_major shared ) readonly buffer block{layout(column_major shared ) buffer int value, layout(column_major shared ) buffer implicitly-sized array of float values})

+0:61            Constant:

+0:61              1 (const int)

+0:61          Constant:

+0:61            2 (const int)

+0:61        Constant:

+0:61          4.700000

+0:62      array length (int)

+0:62        values: direct index for structure (layout(column_major shared ) buffer implicitly-sized array of float)

+0:62          'ro' (layout(column_major shared ) readonly buffer block{layout(column_major shared ) buffer int value, layout(column_major shared ) buffer implicitly-sized array of float values})

+0:62          Constant:

+0:62            1 (const int)

 0:?   Linker Objects

 0:?     'gl_WorkGroupSize' (const 3-component vector of uint)

 0:?       2 (const uint)

@@ -35,6 +67,8 @@
 0:?       4096 (const uint)

 0:?     'total' (const int)

 0:?       66592 (const int)

+0:?     'anon@0' (layout(column_major shared ) buffer block{layout(column_major shared ) buffer int value, layout(column_major shared ) buffer implicitly-sized array of float values})

+0:?     'invalid' (layout(column_major shared ) buffer block{layout(column_major shared ) buffer implicitly-sized array of float values, layout(column_major shared ) buffer int value})

 0:?     'v3' (layout(location=2 ) in 3-component vector of float)

 0:?     'f' (in float)

 0:?     'fo' (out float)

@@ -44,6 +78,7 @@
 0:?     'arrX' (2-element array of int)

 0:?     'arrY' (1-element array of int)

 0:?     'arrZ' (4096-element array of int)

+0:?     'ro' (layout(column_major shared ) readonly buffer block{layout(column_major shared ) buffer int value, layout(column_major shared ) buffer implicitly-sized array of float values})

 

 

 Linked compute stage:

@@ -52,16 +87,46 @@
 Shader version: 430

 local_size = (2, 1, 4096)

 ERROR: node is still EOpNull!

-0:15  Function Definition: main( (void)

-0:15    Function Parameters: 

-0:17    Sequence

-0:17      Barrier (void)

-0:18      MemoryBarrier (void)

-0:19      MemoryBarrierAtomicCounter (void)

-0:20      MemoryBarrierBuffer (void)

-0:21      MemoryBarrierShared (void)

-0:22      MemoryBarrierImage (void)

-0:23      GroupMemoryBarrier (void)

+0:27  Function Definition: main( (void)

+0:27    Function Parameters: 

+0:29    Sequence

+0:29      Barrier (void)

+0:30      MemoryBarrier (void)

+0:31      MemoryBarrierAtomicCounter (void)

+0:32      MemoryBarrierBuffer (void)

+0:33      MemoryBarrierShared (void)

+0:34      MemoryBarrierImage (void)

+0:35      GroupMemoryBarrier (void)

+0:36      move second child to first child (int)

+0:36        value: direct index for structure (layout(column_major shared ) buffer int)

+0:36          'anon@0' (layout(column_major shared ) buffer block{layout(column_major shared ) buffer int value, layout(column_major shared ) buffer implicitly-sized array of float values})

+0:36          Constant:

+0:36            0 (const uint)

+0:36        Convert float to int (int)

+0:36          indirect index (layout(column_major shared ) float)

+0:36            values: direct index for structure (layout(column_major shared ) buffer implicitly-sized array of float)

+0:36              'anon@0' (layout(column_major shared ) buffer block{layout(column_major shared ) buffer int value, layout(column_major shared ) buffer implicitly-sized array of float values})

+0:36              Constant:

+0:36                1 (const uint)

+0:36            'gl_LocalInvocationIndex' (in uint)

+0:59  Function Definition: foo( (void)

+0:59    Function Parameters: 

+0:61    Sequence

+0:61      move second child to first child (float)

+0:61        direct index (layout(column_major shared ) float)

+0:61          values: direct index for structure (layout(column_major shared ) buffer implicitly-sized array of float)

+0:61            'ro' (layout(column_major shared ) readonly buffer block{layout(column_major shared ) buffer int value, layout(column_major shared ) buffer implicitly-sized array of float values})

+0:61            Constant:

+0:61              1 (const int)

+0:61          Constant:

+0:61            2 (const int)

+0:61        Constant:

+0:61          4.700000

+0:62      array length (int)

+0:62        values: direct index for structure (layout(column_major shared ) buffer implicitly-sized array of float)

+0:62          'ro' (layout(column_major shared ) readonly buffer block{layout(column_major shared ) buffer int value, layout(column_major shared ) buffer implicitly-sized array of float values})

+0:62          Constant:

+0:62            1 (const int)

 0:?   Linker Objects

 0:?     'gl_WorkGroupSize' (const 3-component vector of uint)

 0:?       2 (const uint)

@@ -69,6 +134,8 @@
 0:?       4096 (const uint)

 0:?     'total' (const int)

 0:?       66592 (const int)

+0:?     'anon@0' (layout(column_major shared ) buffer block{layout(column_major shared ) buffer int value, layout(column_major shared ) buffer implicitly-sized array of float values})

+0:?     'invalid' (layout(column_major shared ) buffer block{layout(column_major shared ) buffer implicitly-sized array of float values, layout(column_major shared ) buffer int value})

 0:?     'v3' (layout(location=2 ) in 3-component vector of float)

 0:?     'f' (in float)

 0:?     'fo' (out float)

@@ -78,4 +145,5 @@
 0:?     'arrX' (2-element array of int)

 0:?     'arrY' (1-element array of int)

 0:?     'arrZ' (4096-element array of int)

+0:?     'ro' (layout(column_major shared ) readonly buffer block{layout(column_major shared ) buffer int value, layout(column_major shared ) buffer implicitly-sized array of float values})

 

diff --git a/Test/baseResults/specExamples.vert.out b/Test/baseResults/specExamples.vert.out
index 9d02d02..b082a85 100644
--- a/Test/baseResults/specExamples.vert.out
+++ b/Test/baseResults/specExamples.vert.out
@@ -35,10 +35,6 @@
 ERROR: 0:106: 'redeclaration' : cannot change storage, memory, or auxiliary qualification of gl_FrontColor

 ERROR: 0:112: 'ColorIvn' : identifier not previously declared 

 WARNING: 0:118: '' : unknown requalification 

-ERROR: 0:123: '' : memory qualifiers can only be used on image types 

-ERROR: 0:122: '' : memory qualifiers can only be used on image types 

-ERROR: 0:128: '' : memory qualifiers can only be used on image types 

-ERROR: 0:129: '' : memory qualifiers can only be used on image types 

 ERROR: 0:132: 'shared' : not supported in this stage: vertex

 ERROR: 0:134: '' : function does not return a value: funcA

 ERROR: 0:136: '' : function does not return a value: funcB

@@ -47,7 +43,7 @@
 ERROR: 0:192: 'constructor' : constructing from a non-dereferenced array 

 ERROR: 0:193: 'constructor' : constructing from a non-dereferenced array 

 ERROR: 0:194: 'constructor' : constructing from a non-dereferenced array 

-ERROR: 45 compilation errors.  No code generated.

+ERROR: 41 compilation errors.  No code generated.

 

 

 Shader version: 430

@@ -314,8 +310,8 @@
 0:?     'c' (in 4-component vector of float)

 0:?     'd' (in 4-component vector of float)

 0:?     'v' (smooth out 4-component vector of float)

-0:?     'anon@6' (layout(row_major shared ) coherent uniform block{layout(row_major shared ) readonly uniform 4-component vector of float member1, layout(row_major shared ) uniform 4-component vector of float member2})

-0:?     'anon@7' (layout(row_major shared ) uniform block{layout(row_major shared ) coherent readonly uniform 4-component vector of float member1A, layout(row_major shared ) coherent uniform 4-component vector of float member2A})

+0:?     'anon@6' (layout(column_major shared ) coherent buffer block{layout(column_major shared ) readonly buffer 4-component vector of float member1, layout(column_major shared ) buffer 4-component vector of float member2})

+0:?     'anon@7' (layout(column_major shared ) buffer block{layout(column_major shared ) coherent readonly buffer 4-component vector of float member1A, layout(column_major shared ) coherent buffer 4-component vector of float member2A})

 0:?     'shv' (shared 4-component vector of float)

 0:?     'img1' (layout(rgba32f ) uniform image2D)

 0:?     'img2' (layout(rgba32f ) coherent uniform image2D)

@@ -590,8 +586,8 @@
 0:?     'c' (in 4-component vector of float)

 0:?     'd' (in 4-component vector of float)

 0:?     'v' (smooth out 4-component vector of float)

-0:?     'anon@6' (layout(row_major shared ) coherent uniform block{layout(row_major shared ) readonly uniform 4-component vector of float member1, layout(row_major shared ) uniform 4-component vector of float member2})

-0:?     'anon@7' (layout(row_major shared ) uniform block{layout(row_major shared ) coherent readonly uniform 4-component vector of float member1A, layout(row_major shared ) coherent uniform 4-component vector of float member2A})

+0:?     'anon@6' (layout(column_major shared ) coherent buffer block{layout(column_major shared ) readonly buffer 4-component vector of float member1, layout(column_major shared ) buffer 4-component vector of float member2})

+0:?     'anon@7' (layout(column_major shared ) buffer block{layout(column_major shared ) coherent readonly buffer 4-component vector of float member1A, layout(column_major shared ) coherent buffer 4-component vector of float member2A})

 0:?     'shv' (shared 4-component vector of float)

 0:?     'img1' (layout(rgba32f ) uniform image2D)

 0:?     'img2' (layout(rgba32f ) coherent uniform image2D)

diff --git a/Todo.txt b/Todo.txt
index 1a6095c..ade92f5 100644
--- a/Todo.txt
+++ b/Todo.txt
@@ -197,9 +197,10 @@
       + Clarify that textureGatherOffset() can take non-constants for the offsets.
     GLSL 4.3
       - Add shader storage buffer objects, as per the ARB_shader_storage_buffer_object extension. This includes 
-            - allowing the last member of a storage buffer block to be an array that does not know its size until render time
+            + allowing the last member of a storage buffer block to be an array that does not know its size until render time
             - read/write memory shared with the application and other shader invocations
-            - adding the std430 layout qualifier for shader storage blocks
+            + adding the std430 layout qualifier for shader storage blocks
+            - add atomic built-ins
       - Allow .length() on all arrays; returning a compile-time constant or not, depending on how the 
         array is sized, as per the ARB_shader_storage_buffer_object extension.
       - Be clear that implicit array sizing is only within a stage, not cross stage.
diff --git a/glslang/Include/BaseTypes.h b/glslang/Include/BaseTypes.h
index 5b9b2f5..fd44951 100644
--- a/glslang/Include/BaseTypes.h
+++ b/glslang/Include/BaseTypes.h
@@ -67,8 +67,8 @@
     EvqConst,         // User-defined constant values, will be semantically constant and constant folded
     EvqVaryingIn,     // pipeline input, read only
     EvqVaryingOut,    // pipeline ouput, read/write
-    EvqUniform,       // read only, shader with app
-    EvqBuffer,        // read only, shader with app
+    EvqUniform,       // read only, shared with app
+    EvqBuffer,        // read/write, shared with app
     EvqShared,        // compute shader's read/write 'shared' qualifier
     
     // parameters
diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h
index 4d5c354..82d247c 100644
--- a/glslang/Include/Types.h
+++ b/glslang/Include/Types.h
@@ -406,7 +406,7 @@
         }
     }
 
-    bool isUniform() const
+    bool isUniformOrBuffer() const
     {
         switch (storage) {
         case EvqUniform:
@@ -802,10 +802,15 @@
         vectorSize = 0;
     }
 
-    bool isScalar()
+    bool isScalar() const
     {
         return matrixCols == 0 && vectorSize == 1 && arraySizes == 0 && userDef == 0;
     }
+
+    bool isImage() const
+    {
+        return basicType == EbtSampler && sampler.image;
+    }
 };
 
 typedef std::map<TTypeList*, TTypeList*> TStructureMap;
@@ -1008,9 +1013,11 @@
     virtual bool isVector() const { return vectorSize > 1; }
     virtual bool isMatrix() const { return matrixCols ? true : false; }
     virtual bool isArray()  const { return arraySizes != 0; }
-    virtual bool isImplicitlySizedArray() const { return isArray() && ! getArraySize(); }
-    virtual bool isExplicitlySizedArray() const { return ! isImplicitlySizedArray(); }
+    virtual bool isImplicitlySizedArray() const { return isArray() && ! getArraySize() && qualifier.storage != EvqBuffer; }
+    virtual bool isExplicitlySizedArray() const { return isArray() && getArraySize(); }
+    virtual bool isRuntimeSizedArray() const { return isArray() && ! getArraySize() && qualifier.storage == EvqBuffer; }
     virtual bool isStruct() const { return structure != 0; }
+    virtual bool isImage() const { return basicType == EbtSampler && getSampler().image; }
 
     // Recursively checks if the type contains the given basic type
     virtual bool containsBasicType(TBasicType checkType) const
diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp
index 4da9aa7..a3484a9 100644
--- a/glslang/MachineIndependent/ParseHelper.cpp
+++ b/glslang/MachineIndependent/ParseHelper.cpp
@@ -526,10 +526,10 @@
 void TParseContext::handleIndexLimits(TSourceLoc loc, TIntermTyped* base, TIntermTyped* index)
 {
     if ((! limits.generalSamplerIndexing && base->getBasicType() == EbtSampler) ||
-        (! limits.generalUniformIndexing && base->getQualifier().isUniform() && language != EShLangVertex) ||
+        (! limits.generalUniformIndexing && base->getQualifier().isUniformOrBuffer() && language != EShLangVertex) ||
         (! limits.generalAttributeMatrixVectorIndexing && base->getQualifier().isPipeInput() && language == EShLangVertex && (base->getType().isMatrix() || base->getType().isVector())) ||
         (! limits.generalConstantMatrixVectorIndexing && base->getAsConstantUnion()) ||
-        (! limits.generalVariableIndexing && ! base->getType().getQualifier().isUniform() &&
+        (! limits.generalVariableIndexing && ! base->getType().getQualifier().isUniformOrBuffer() &&
                                              ! base->getType().getQualifier().isPipeInput() &&
                                              ! base->getType().getQualifier().isPipeOutput() &&
                                                base->getType().getQualifier().storage != EvqConst) ||
@@ -1062,7 +1062,10 @@
     else {
         const TType& type = intermNode->getAsTyped()->getType();
         if (type.isArray()) {
-            if (type.isImplicitlySizedArray()) {
+            if (type.isRuntimeSizedArray()) {
+                // Create a unary op and let the back end handle it
+                return intermediate.addBuiltInFunctionCall(loc, EOpArrayLength, true, intermNode, TType(EbtInt));
+            } else if (type.isImplicitlySizedArray()) {
                 if (intermNode->getAsSymbolNode() && isIoResizeArray(type)) {
                     // We could be between a layout declaration that gives a built-in io array implicit size and 
                     // a user redeclaration of that array, meaning we have to substitute its implicit size here 
@@ -1565,12 +1568,16 @@
     case EvqConst:          message = "can't modify a const";        break;
     case EvqConstReadOnly:  message = "can't modify a const";        break;
     case EvqVaryingIn:      message = "can't modify shader input";   break;
-    case EvqUniform:        message = "can't modify a uniform";      break;
     case EvqInstanceId:     message = "can't modify gl_InstanceID";  break;
     case EvqVertexId:       message = "can't modify gl_VertexID";    break;
     case EvqFace:           message = "can't modify gl_FrontFace";   break;
     case EvqFragCoord:      message = "can't modify gl_FragCoord";   break;
     case EvqPointCoord:     message = "can't modify gl_PointCoord";  break;
+    case EvqUniform:        message = "can't modify a uniform";      break;
+    case EvqBuffer:
+        if (node->getQualifier().readonly)
+            message = "can't modify a readonly buffer";
+        break;
     default:
 
         //
@@ -1911,6 +1918,9 @@
     if (! symbolTable.atGlobalLevel())
         return;
 
+    if (qualifier.isMemory() && ! publicType.isImage() && publicType.qualifier.storage != EvqBuffer)
+        error(loc, "memory qualifiers cannot be used on this type", "", "");
+
     if (qualifier.storage != EvqVaryingIn && qualifier.storage != EvqVaryingOut)
         return;
 
@@ -3281,8 +3291,8 @@
     // Check packing and matrix 
     if (qualifier.hasUniformLayout()) {
         switch (qualifier.storage) {
-        case EvqBuffer:
         case EvqUniform:
+        case EvqBuffer:
             if (type.getBasicType() != EbtBlock) {
                 if (qualifier.hasMatrix())
                     error(loc, "cannot specify matrix layout on a variable declaration", "layout", "");
@@ -3396,7 +3406,7 @@
 
     // Image format
     if (qualifier.hasFormat()) {
-        if (type.getBasicType() != EbtSampler || ! type.getSampler().image)
+        if (! type.isImage())
             error(loc, "only apply to images", TQualifier::getLayoutFormatString(qualifier.layoutFormat), "");
         else {
             if (type.getSampler().type == EbtFloat && qualifier.layoutFormat > ElfFloatGuard)
@@ -3406,10 +3416,8 @@
             if (type.getSampler().type == EbtUint && qualifier.layoutFormat < ElfIntGuard)
                 error(loc, "does not apply to unsigned integer images", TQualifier::getLayoutFormatString(qualifier.layoutFormat), "");
         }
-    } else if (type.getBasicType() == EbtSampler && type.getSampler().image && !qualifier.writeonly)
+    } else if (type.isImage() && ! qualifier.writeonly)
         error(loc, "image variables not declared 'writeonly' must have a format layout qualifier", "", "");
-    if (qualifier.isMemory() && (type.getBasicType() != EbtSampler || ! type.getSampler().image))
-        error(loc, "memory qualifiers can only be used on image types", "", "");
 }
 
 // Do layout error checking that can be done within a qualifier proper, not needing to know
@@ -3470,7 +3478,7 @@
     }
 
     if (qualifier.hasBinding()) {
-        if (qualifier.storage != EvqUniform && qualifier.storage != EvqBuffer)
+        if (! qualifier.isUniformOrBuffer())
             error(loc, "requires uniform or buffer storage qualifier", "binding", "");
     }
     if (qualifier.hasStream()) {
@@ -3482,7 +3490,7 @@
             error(loc, "can only be used on an output", "xfb layout qualifier", "");
     }
     if (qualifier.hasUniformLayout()) {
-        if (! (qualifier.storage == EvqUniform || qualifier.storage == EvqBuffer)) {
+        if (! qualifier.isUniformOrBuffer()) {
             if (qualifier.hasMatrix() || qualifier.hasPacking())
                 error(loc, "matrix or packing qualifiers can only be used on a uniform or buffer", "layout", "");
             if (qualifier.hasOffset() || qualifier.hasAlign())
@@ -4122,14 +4130,14 @@
         arraySizeRequiredCheck(loc, arraySizes->getSize());
 
     switch (currentBlockQualifier.storage) {
-    case EvqBuffer:
-        requireProfile(loc, ECoreProfile | ECompatibilityProfile, "buffer block");
-        profileRequires(loc, ECoreProfile | ECompatibilityProfile, 430, 0, "buffer block");
-        break;
     case EvqUniform:
         profileRequires(loc, EEsProfile, 300, 0, "uniform block");
         profileRequires(loc, ENoProfile, 140, 0, "uniform block");
         break;
+    case EvqBuffer:
+        requireProfile(loc, ECoreProfile | ECompatibilityProfile, "buffer block");
+        profileRequires(loc, ECoreProfile | ECompatibilityProfile, 430, 0, "buffer block");
+        break;
     case EvqVaryingIn:
         requireProfile(loc, ~EEsProfile, "input block");
         profileRequires(loc, ~EEsProfile, 150, GL_ARB_separate_shader_objects, "input block");
@@ -4147,16 +4155,19 @@
 
     // fix and check for member storage qualifiers and types that don't belong within a block
     for (unsigned int member = 0; member < typeList.size(); ++member) {
-        TQualifier& memberQualifier = typeList[member].type->getQualifier();
+        TType& memberType = *typeList[member].type;
+        TQualifier& memberQualifier = memberType.getQualifier();
         TSourceLoc memberLoc = typeList[member].loc;
         pipeInOutFix(memberLoc, memberQualifier);
         if (memberQualifier.storage != EvqTemporary && memberQualifier.storage != EvqGlobal && memberQualifier.storage != currentBlockQualifier.storage)
-            error(memberLoc, "member storage qualifier cannot contradict block storage qualifier", typeList[member].type->getFieldName().c_str(), "");
+            error(memberLoc, "member storage qualifier cannot contradict block storage qualifier", memberType.getFieldName().c_str(), "");
         memberQualifier.storage = currentBlockQualifier.storage;
-        if (currentBlockQualifier.storage == EvqUniform && (memberQualifier.isInterpolation() || memberQualifier.isAuxiliary()))
-            error(memberLoc, "member of uniform block cannot have an auxiliary or interpolation qualifier", typeList[member].type->getFieldName().c_str(), "");
+        if ((currentBlockQualifier.storage == EvqUniform || currentBlockQualifier.storage == EvqBuffer) && (memberQualifier.isInterpolation() || memberQualifier.isAuxiliary()))
+            error(memberLoc, "member of uniform or buffer block cannot have an auxiliary or interpolation qualifier", memberType.getFieldName().c_str(), "");
+        if (memberType.isRuntimeSizedArray() && member < typeList.size() - 1)
+            error(memberLoc, "only the last member of a buffer block can be run-time sized", memberType.getFieldName().c_str(), "");
 
-        TBasicType basicType = typeList[member].type->getBasicType();
+        TBasicType basicType = memberType.getBasicType();
         if (basicType == EbtSampler)
             error(memberLoc, "member of block cannot be a sampler type", typeList[member].type->getFieldName().c_str(), "");
     }
@@ -4179,8 +4190,8 @@
 
     TQualifier defaultQualification;
     switch (currentBlockQualifier.storage) {
-    case EvqBuffer:     defaultQualification = globalBufferDefaults;     break;
     case EvqUniform:    defaultQualification = globalUniformDefaults;    break;
+    case EvqBuffer:     defaultQualification = globalBufferDefaults;     break;
     case EvqVaryingIn:  defaultQualification = globalInputDefaults;      break;
     case EvqVaryingOut: defaultQualification = globalOutputDefaults;     break;
     default:            defaultQualification.clear();                    break;
@@ -4401,7 +4412,7 @@
 //
 void TParseContext::fixBlockUniformOffsets(TSourceLoc loc, TQualifier& qualifier, TTypeList& typeList)
 {
-    if (qualifier.storage != EvqUniform && qualifier.storage != EvqBuffer)
+    if (! qualifier.isUniformOrBuffer())
         return;
     if (qualifier.layoutPacking != ElpStd140 && qualifier.layoutPacking != ElpStd430)
         return;
diff --git a/glslang/MachineIndependent/glslang.y b/glslang/MachineIndependent/glslang.y
index bc9ac87..1e20693 100644
--- a/glslang/MachineIndependent/glslang.y
+++ b/glslang/MachineIndependent/glslang.y
@@ -1213,7 +1213,7 @@
     | BUFFER {

         parseContext.globalCheck($1.loc, "buffer");

         $$.init($1.loc);

-        $$.qualifier.storage = EvqUniform; // TODO: 4.0 functionality: implement BUFFER

+        $$.qualifier.storage = EvqBuffer;

     }

     | SHARED {

         parseContext.requireProfile($1.loc, ~EEsProfile, "shared");

diff --git a/glslang/MachineIndependent/intermOut.cpp b/glslang/MachineIndependent/intermOut.cpp
index 955f31a..4914070 100644
--- a/glslang/MachineIndependent/intermOut.cpp
+++ b/glslang/MachineIndependent/intermOut.cpp
@@ -257,6 +257,8 @@
     case EOpAny:            out.debug << "any";                  break;
     case EOpAll:            out.debug << "all";                  break;
 
+    case EOpArrayLength:    out.debug << "array length";         break;
+
     case EOpEmitStreamVertex:   out.debug << "EmitStreamVertex";   break;
     case EOpEndStreamPrimitive: out.debug << "EndStreamPrimitive"; break;
 
diff --git a/glslang/MachineIndependent/linkValidate.cpp b/glslang/MachineIndependent/linkValidate.cpp
index 1c4d5b8..3628f99 100644
--- a/glslang/MachineIndependent/linkValidate.cpp
+++ b/glslang/MachineIndependent/linkValidate.cpp
@@ -604,13 +604,15 @@
         set = 0;

     else if (qualifier.isPipeOutput())

         set = 1;

-    else if (qualifier.isUniform())

+    else if (qualifier.storage == EvqUniform)

         set = 2;

+    else if (qualifier.storage == EvqBuffer)

+        set = 3;

     else

         return -1;

 

     int size;

-    if (qualifier.isUniform()) {

+    if (qualifier.isUniformOrBuffer()) {

         if (type.isArray())

             size = type.getArraySize();

         else

diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h
index 463aa86..54aa6dd 100644
--- a/glslang/MachineIndependent/localintermediate.h
+++ b/glslang/MachineIndependent/localintermediate.h
@@ -310,7 +310,7 @@
     TGraph callGraph;
 
     std::set<TString> ioAccessed;       // set of names of statically read/written I/O that might need extra checking
-    std::vector<TIoRange> usedIo[3];    // sets of used locations, one for each of in, out, and uniform
+    std::vector<TIoRange> usedIo[4];    // sets of used locations, one for each of in, out, uniform and buffers
     std::vector<TXfbBuffer> xfbBuffers; // all the data we need to track per xfb buffer
 
 private:
diff --git a/glslang/MachineIndependent/reflection.cpp b/glslang/MachineIndependent/reflection.cpp
index ac9f3b6..6c1299b 100644
--- a/glslang/MachineIndependent/reflection.cpp
+++ b/glslang/MachineIndependent/reflection.cpp
@@ -265,7 +265,7 @@
         // We have an array or structure or block dereference, see if it's a uniform 

         // based dereference (if not, skip it).

         TIntermSymbol* base = findBase(topNode);

-        if (! base || base->getQualifier().storage != EvqUniform)

+        if (! base || ! base->getQualifier().isUniformOrBuffer())

             return;

             

         // See if we've already processed this (e.g., in the middle of something