diff --git a/StandAlone/StandAlone.cpp b/StandAlone/StandAlone.cpp
index 8d3f5cac8e58d25be8affde27f14a7c94c68fd4c..b16f139a9d01db5b290cfc81bb2648ed274f0d8d 100644
--- a/StandAlone/StandAlone.cpp
+++ b/StandAlone/StandAlone.cpp
@@ -155,6 +155,7 @@ const char* DefaultConfig =
     "MaxFragmentInputComponents 128\n"
     "MaxImageUnits 8\n"
     "MaxCombinedImageUnitsAndFragmentOutputs 8\n"
+    "MaxCombinedShaderOutputResources 8\n"
     "MaxImageSamples 0\n"
     "MaxVertexImageUniforms 0\n"
     "MaxTessControlImageUniforms 0\n"
@@ -316,6 +317,8 @@ void ProcessConfigFile()
             Resources.maxImageUnits = value;
         else if (strcmp(token, "MaxCombinedImageUnitsAndFragmentOutputs") == 0)
             Resources.maxCombinedImageUnitsAndFragmentOutputs = value;
+        else if (strcmp(token, "MaxCombinedShaderOutputResources") == 0)
+            Resources.maxCombinedShaderOutputResources = value;
         else if (strcmp(token, "MaxImageSamples") == 0)
             Resources.maxImageSamples = value;
         else if (strcmp(token, "MaxVertexImageUniforms") == 0)
diff --git a/Test/130.frag b/Test/130.frag
index a5903928042dfd632221e70ed98b548893e68c4d..3e394110b5516f4ac1a29095dfabff25bf242bb8 100644
--- a/Test/130.frag
+++ b/Test/130.frag
@@ -148,4 +148,22 @@ in float gl_FogFragCoord;
 #extension GL_ARB_separate_shader_objects : enable
 
 in float gl_FogFragCoord;
-in int gl_FogFragCoord;
+in int gl_FogFragCoord;    // ERROR
+
+layout(early_fragment_tests) in;         // ERROR
+layout(r32i) uniform iimage2D iimg2Dbad; // ERROR
+
+#extension GL_ARB_shader_image_load_store : enable
+
+layout(early_fragment_tests) in;
+
+layout(r32i) uniform iimage2D iimg2D;
+
+void qux2()
+{
+    int i;
+    imageAtomicCompSwap(iimg2D, ivec2(i,i), i, i);
+    ivec4 pos = imageLoad(iimg2D, ivec2(i,i));
+}
+
+layout(early_fragment_tests) out;         // ERROR
diff --git a/Test/150.geom b/Test/150.geom
index 2edf95076c74ce6c7a53ffdda966815d07377cc1..8f13a60c25d06ee9f6f9b21c4c263387f30eeb38 100644
--- a/Test/150.geom
+++ b/Test/150.geom
@@ -83,7 +83,7 @@ out outbn2 {
 } outbi;
 
 layout(lines) out;  // ERROR, not on output
-layout(lines_adjancency) in;
+layout(lines_adjacency) in;
 layout(triangles) in;             // ERROR, can't change it
 layout(triangles_adjacency) in;   // ERROR, can't change it
 layout(invocations = 4) in;       // ERROR, not until 4.0
diff --git a/Test/420.vert b/Test/420.vert
index de3534f2dbad7a1be82cdcc46e676af9be498a73..93a9874fa2d48f3b0859b6a5f8df7e56174e9072 100644
--- a/Test/420.vert
+++ b/Test/420.vert
@@ -99,3 +99,46 @@ void bar23444()
 
 const int comma0 = (2, 3);  // ERROR
 int comma1[(2, 3)];   // ERROR
+
+layout(r32i) uniform iimage2D iimg2D;
+layout(rgba32i) uniform iimage2D iimg2Drgba;
+layout(rgba32f) uniform image2D img2Drgba;
+layout(r32ui) uniform uimage2D uimg2D;
+uniform image2DMS img2DMS; // ERROR image variables not declared writeonly must have format layout qualifier
+uniform writeonly image2DMS img2DMSWO;
+void qux()
+{
+    int i = aoeu;
+    imageAtomicCompSwap(iimg2D, ivec2(i,i), i, i);
+    imageAtomicAdd(uimg2D, ivec2(i,i), uint(i));
+    imageAtomicMin(iimg2Drgba, ivec2(i,i), i); // ERROR iimg2Drgba does not have r32i layout
+    imageAtomicMax(img2Drgba, ivec2(i,i), i);  // ERROR img2Drgba is not integer image
+    ivec4 pos = imageLoad(iimg2D, ivec2(i,i));
+    vec4 col = imageLoad(img2DMS, ivec2(i,i), i);
+    imageStore(img2DMSWO, ivec2(i,i), i, vec4(0));
+    imageLoad(img2DMSWO, ivec2(i,i), i);       // ERROR, drops writeonly
+}
+
+volatile float vol; // ERROR, not an image
+readonly int vol2;  // ERROR, not an image
+
+void passr(coherent readonly iimage2D image)
+{
+}
+
+layout(r32i) coherent readonly uniform iimage2D qualim1;
+layout(r32i) coherent restrict readonly uniform iimage2D qualim2;
+
+void passrc()
+{
+    passr(qualim1);
+    passr(qualim2);   // ERROR, drops restrict
+    passr(iimg2D);
+}
+
+layout(rg8i) uniform uimage2D i1bad;     // ERROR, type mismatch
+layout(rgba32i) uniform image2D i2bad;   // ERROR, type mismatch
+layout(rgba32f) uniform uimage2D i3bad;  // ERROR, type mismatch
+layout(r8_snorm) uniform iimage2D i4bad; // ERROR, type mismatch
+layout(rgba32ui) uniform iimage2D i5bad; // ERROR, type mismatch
+layout(r8ui) uniform iimage2D i6bad;     // ERROR, type mismatch
diff --git a/Test/baseResults/130.frag.out b/Test/baseResults/130.frag.out
index 6b1dca516f21b3da48e54375a2d1c32efe7dc13a..b2d2ed24b0086255eaf126a8460e388c0404cda4 100644
--- a/Test/baseResults/130.frag.out
+++ b/Test/baseResults/130.frag.out
@@ -25,16 +25,22 @@ ERROR: 0:143: 'length' : method does not accept any arguments
 ERROR: 0:146: 'gl_FogFragCoord' : identifiers starting with "gl_" are reserved 
 ERROR: 0:151: 'int' : must be qualified as flat in
 ERROR: 0:151: 'redeclaration' : cannot change the type of gl_FogFragCoord
-ERROR: 24 compilation errors.  No code generated.
+ERROR: 0:153: 'early_fragment_tests' : not supported for this version or the enabled extensions 
+ERROR: 0:154: 'image load store' : not supported for this version or the enabled extensions 
+ERROR: 0:154: 'iimage2D' : Reserved word. 
+ERROR: 0:169: 'early_fragment_tests' : can only apply to 'in' 
+ERROR: 28 compilation errors.  No code generated.
 
 
 Shader version: 130
 Requested GL_ARB_gpu_shader5
 Requested GL_ARB_separate_shader_objects
+Requested GL_ARB_shader_image_load_store
 Requested GL_ARB_shading_language_420pack
 Requested GL_ARB_texture_cube_map_array
 Requested GL_ARB_texture_gather
 Requested GL_ARB_texture_rectangle
+using early_fragment_tests
 ERROR: node is still EOpNull!
 0:16  Function Definition: main( (void)
 0:16    Function Parameters: 
@@ -348,6 +354,24 @@ ERROR: node is still EOpNull!
 0:141        0.000000
 0:143      Constant:
 0:143        1 (const int)
+0:162  Function Definition: qux2( (void)
+0:162    Function Parameters: 
+0:?     Sequence
+0:165      Function Call: imageAtomicCompSwap(iI21;vi2;i1;i1; (int)
+0:165        'iimg2D' (layout(r32i ) uniform iimage2D)
+0:165        Construct ivec2 (2-component vector of int)
+0:165          'i' (int)
+0:165          'i' (int)
+0:165        'i' (int)
+0:165        'i' (int)
+0:166      Sequence
+0:166        move second child to first child (4-component vector of int)
+0:166          'pos' (4-component vector of int)
+0:166          Function Call: imageLoad(iI21;vi2; (4-component vector of int)
+0:166            'iimg2D' (layout(r32i ) uniform iimage2D)
+0:166            Construct ivec2 (2-component vector of int)
+0:166              'i' (int)
+0:166              'i' (int)
 0:?   Linker Objects
 0:?     'a' (3-component vector of float)
 0:?     'b' (float)
@@ -377,6 +401,8 @@ ERROR: node is still EOpNull!
 0:?     'instanceName' (layout(binding=0 column_major shared ) uniform block{layout(column_major shared ) uniform int a})
 0:?     'bounds' (layout(binding=0 ) uniform sampler2D)
 0:?     'gl_FogFragCoord' (smooth in float)
+0:?     'iimg2Dbad' (layout(r32i ) uniform iimage2D)
+0:?     'iimg2D' (layout(r32i ) uniform iimage2D)
 
 
 Linked fragment stage:
@@ -385,10 +411,12 @@ Linked fragment stage:
 Shader version: 130
 Requested GL_ARB_gpu_shader5
 Requested GL_ARB_separate_shader_objects
+Requested GL_ARB_shader_image_load_store
 Requested GL_ARB_shading_language_420pack
 Requested GL_ARB_texture_cube_map_array
 Requested GL_ARB_texture_gather
 Requested GL_ARB_texture_rectangle
+using early_fragment_tests
 ERROR: node is still EOpNull!
 0:16  Function Definition: main( (void)
 0:16    Function Parameters: 
@@ -702,6 +730,24 @@ ERROR: node is still EOpNull!
 0:141        0.000000
 0:143      Constant:
 0:143        1 (const int)
+0:162  Function Definition: qux2( (void)
+0:162    Function Parameters: 
+0:?     Sequence
+0:165      Function Call: imageAtomicCompSwap(iI21;vi2;i1;i1; (int)
+0:165        'iimg2D' (layout(r32i ) uniform iimage2D)
+0:165        Construct ivec2 (2-component vector of int)
+0:165          'i' (int)
+0:165          'i' (int)
+0:165        'i' (int)
+0:165        'i' (int)
+0:166      Sequence
+0:166        move second child to first child (4-component vector of int)
+0:166          'pos' (4-component vector of int)
+0:166          Function Call: imageLoad(iI21;vi2; (4-component vector of int)
+0:166            'iimg2D' (layout(r32i ) uniform iimage2D)
+0:166            Construct ivec2 (2-component vector of int)
+0:166              'i' (int)
+0:166              'i' (int)
 0:?   Linker Objects
 0:?     'a' (3-component vector of float)
 0:?     'b' (float)
@@ -731,4 +777,6 @@ ERROR: node is still EOpNull!
 0:?     'instanceName' (layout(binding=0 column_major shared ) uniform block{layout(column_major shared ) uniform int a})
 0:?     'bounds' (layout(binding=0 ) uniform sampler2D)
 0:?     'gl_FogFragCoord' (smooth in float)
+0:?     'iimg2Dbad' (layout(r32i ) uniform iimage2D)
+0:?     'iimg2D' (layout(r32i ) uniform iimage2D)
 
diff --git a/Test/baseResults/150.geom.out b/Test/baseResults/150.geom.out
index 1b0961f318e153e615a721c570df9161f53ceb81..8d0445700f586f0dc340d5865d271a68a9a536d8 100644
--- a/Test/baseResults/150.geom.out
+++ b/Test/baseResults/150.geom.out
@@ -37,7 +37,7 @@ ERROR: 32 compilation errors.  No code generated.
 Shader version: 150
 invocations = 4
 max_vertices = 200
-input primitive = lines_adjancency
+input primitive = lines_adjacency
 output primitive = triangle_strip
 ERROR: node is still EOpNull!
 0:25  Function Definition: main( (void)
@@ -156,7 +156,7 @@ Linked geometry stage:
 Shader version: 150
 invocations = 4
 max_vertices = 200
-input primitive = lines_adjancency
+input primitive = lines_adjacency
 output primitive = triangle_strip
 ERROR: node is still EOpNull!
 0:25  Function Definition: main( (void)
diff --git a/Test/baseResults/150.tesc.out b/Test/baseResults/150.tesc.out
index f60022395f900c7a4fe9f4472842ab0629bc7a17..5db3e497cb41e8d3b949ae20618ee2b7c808a03b 100644
--- a/Test/baseResults/150.tesc.out
+++ b/Test/baseResults/150.tesc.out
@@ -215,9 +215,9 @@ ERROR: node is still EOpNull!
 
 400.tesc
 Warning, version 400 is not yet complete; most version-specific features are present, but some are missing.
-ERROR: 0:6: 'quads' : unrecognized layout identifier, or qualifier requires assignemnt (e.g., binding = 4) 
-ERROR: 0:7: 'ccw' : unrecognized layout identifier, or qualifier requires assignemnt (e.g., binding = 4) 
-ERROR: 0:8: 'fractional_even_spacing' : unrecognized layout identifier, or qualifier requires assignemnt (e.g., binding = 4) 
+ERROR: 0:6: 'quads' : unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4) 
+ERROR: 0:7: 'ccw' : unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4) 
+ERROR: 0:8: 'fractional_even_spacing' : unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4) 
 ERROR: 0:10: 'patch' : can only use on output in tessellation-control shader 
 ERROR: 0:39: 'vertices' : can only apply to 'out' 
 ERROR: 0:40: 'vertices' : cannot change previously set layout value 
diff --git a/Test/baseResults/300layout.vert.out b/Test/baseResults/300layout.vert.out
index 52de07b8e40d6a188544acab2f98621bd825f6d3..f954252354293b2de28be684b272580218300244 100644
--- a/Test/baseResults/300layout.vert.out
+++ b/Test/baseResults/300layout.vert.out
@@ -15,9 +15,10 @@ ERROR: 0:38: 'output block' : not supported with this profile: es
 ERROR: 0:42: 'location qualifier on output' : not supported in this stage: vertex
 ERROR: 0:50: 'shared' : not supported with this profile: es
 ERROR: 0:50: 'shared' : not supported in this stage: vertex
+ERROR: 0:50: '' : memory qualifiers can only be used on image types 
 ERROR: 0:54: 'layout' : cannot specify packing on a variable declaration 
 ERROR: 0:57: 'location' : overlapping use of location 40
-ERROR: 18 compilation errors.  No code generated.
+ERROR: 19 compilation errors.  No code generated.
 
 
 Shader version: 300
diff --git a/Test/baseResults/400.tesc.out b/Test/baseResults/400.tesc.out
index 8dab6f6c6b036a5ad10378e9209ffd6ab9465981..79baf2e8e444a3db8e018eacfdceb1cdaa8dcaf6 100644
--- a/Test/baseResults/400.tesc.out
+++ b/Test/baseResults/400.tesc.out
@@ -1,8 +1,8 @@
 400.tesc
 Warning, version 400 is not yet complete; most version-specific features are present, but some are missing.
-ERROR: 0:6: 'quads' : unrecognized layout identifier, or qualifier requires assignemnt (e.g., binding = 4) 
-ERROR: 0:7: 'ccw' : unrecognized layout identifier, or qualifier requires assignemnt (e.g., binding = 4) 
-ERROR: 0:8: 'fractional_even_spacing' : unrecognized layout identifier, or qualifier requires assignemnt (e.g., binding = 4) 
+ERROR: 0:6: 'quads' : unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4) 
+ERROR: 0:7: 'ccw' : unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4) 
+ERROR: 0:8: 'fractional_even_spacing' : unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4) 
 ERROR: 0:10: 'patch' : can only use on output in tessellation-control shader 
 ERROR: 0:39: 'vertices' : can only apply to 'out' 
 ERROR: 0:40: 'vertices' : cannot change previously set layout value 
diff --git a/Test/baseResults/420.vert.out b/Test/baseResults/420.vert.out
index 0041a242bd0b6437317629c6bef8da43836b8e0f..94f849b8b9c13591693e909787135000e717992d 100644
--- a/Test/baseResults/420.vert.out
+++ b/Test/baseResults/420.vert.out
@@ -34,7 +34,20 @@ ERROR: 0:86: 'patch' : not supported in this stage: vertex
 ERROR: 0:100: '=' : global const initializers must be constant 'const int'
 ERROR: 0:101: '' : constant expression required 
 ERROR: 0:101: '' : array size must be a constant integer expression 
-ERROR: 33 compilation errors.  No code generated.
+ERROR: 0:107: '' : image variables not declared 'writeonly' must have a format layout qualifier 
+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: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 
+ERROR: 0:141: 'rgba32f' : does not apply to unsigned integer images 
+ERROR: 0:142: 'r8_snorm' : does not apply to signed integer images 
+ERROR: 0:143: 'rgba32ui' : does not apply to signed integer images 
+ERROR: 0:144: 'r8ui' : does not apply to signed integer images 
+ERROR: 46 compilation errors.  No code generated.
 
 
 Shader version: 420
@@ -73,7 +86,7 @@ ERROR: node is still EOpNull!
 0:42        No loop body
 0:50  Function Definition: bar(vf4; (void)
 0:50    Function Parameters: 
-0:50      'v' (in 4-component vector of float)
+0:50      'v' (volatile in 4-component vector of float)
 0:?     Sequence
 0:53      's' (int)
 0:54      's' (int)
@@ -146,6 +159,84 @@ ERROR: node is still EOpNull!
 0:97          'a' (int)
 0:97          Constant:
 0:97            -1 (const int)
+0:109  Function Definition: qux( (void)
+0:109    Function Parameters: 
+0:111    Sequence
+0:111      Sequence
+0:111        move second child to first child (int)
+0:111          'i' (int)
+0:111          aoeu: direct index for structure (layout(column_major shared ) uniform int)
+0:111            'anon@0' (layout(binding=7 column_major shared ) uniform block{layout(column_major shared ) uniform int aoeu})
+0:111            Constant:
+0:111              0 (const uint)
+0:112      Function Call: imageAtomicCompSwap(iI21;vi2;i1;i1; (int)
+0:112        'iimg2D' (layout(r32i ) uniform iimage2D)
+0:112        Construct ivec2 (2-component vector of int)
+0:112          'i' (int)
+0:112          'i' (int)
+0:112        'i' (int)
+0:112        'i' (int)
+0:113      Function Call: imageAtomicAdd(uI21;vi2;u1; (uint)
+0:113        'uimg2D' (layout(r32ui ) uniform uimage2D)
+0:113        Construct ivec2 (2-component vector of int)
+0:113          'i' (int)
+0:113          'i' (int)
+0:113        Convert int to uint (uint)
+0:113          'i' (int)
+0:114      Function Call: imageAtomicMin(iI21;vi2;i1; (int)
+0:114        'iimg2Drgba' (layout(rgba32i ) uniform iimage2D)
+0:114        Construct ivec2 (2-component vector of int)
+0:114          'i' (int)
+0:114          'i' (int)
+0:114        'i' (int)
+0:115      Constant:
+0:115        0.000000
+0:116      Sequence
+0:116        move second child to first child (4-component vector of int)
+0:116          'pos' (4-component vector of int)
+0:116          Function Call: imageLoad(iI21;vi2; (4-component vector of int)
+0:116            'iimg2D' (layout(r32i ) uniform iimage2D)
+0:116            Construct ivec2 (2-component vector of int)
+0:116              'i' (int)
+0:116              'i' (int)
+0:117      Sequence
+0:117        move second child to first child (4-component vector of float)
+0:117          'col' (4-component vector of float)
+0:117          Function Call: imageLoad(I21;vi2;i1; (4-component vector of float)
+0:117            'img2DMS' (uniform image2DMS)
+0:117            Construct ivec2 (2-component vector of int)
+0:117              'i' (int)
+0:117              'i' (int)
+0:117            'i' (int)
+0:118      Function Call: imageStore(I21;vi2;i1;vf4; (void)
+0:118        'img2DMSWO' (writeonly uniform image2DMS)
+0:118        Construct ivec2 (2-component vector of int)
+0:118          'i' (int)
+0:118          'i' (int)
+0:118        'i' (int)
+0:118        Constant:
+0:118          0.000000
+0:118          0.000000
+0:118          0.000000
+0:118          0.000000
+0:119      Function Call: imageLoad(I21;vi2;i1; (4-component vector of float)
+0:119        'img2DMSWO' (writeonly uniform image2DMS)
+0:119        Construct ivec2 (2-component vector of int)
+0:119          'i' (int)
+0:119          'i' (int)
+0:119        'i' (int)
+0:125  Function Definition: passr(iI21; (void)
+0:125    Function Parameters: 
+0:125      'image' (coherent readonly in iimage2D)
+0:132  Function Definition: passrc( (void)
+0:132    Function Parameters: 
+0:134    Sequence
+0:134      Function Call: passr(iI21; (void)
+0:134        'qualim1' (layout(r32i ) coherent readonly uniform iimage2D)
+0:135      Function Call: passr(iI21; (void)
+0:135        'qualim2' (layout(r32i ) coherent restrict readonly uniform iimage2D)
+0:136      Function Call: passr(iI21; (void)
+0:136        'iimg2D' (layout(r32i ) uniform iimage2D)
 0:?   Linker Objects
 0:?     'v2' (smooth out 2-component vector of float)
 0:?     'bad' (in 10-element array of 4-component vector of float)
@@ -180,6 +271,22 @@ ERROR: node is still EOpNull!
 0:?     'patchOut' (smooth patch out 4-component vector of float)
 0:?     'comma0' (int)
 0:?     'comma1' (1-element array of int)
+0:?     'iimg2D' (layout(r32i ) uniform iimage2D)
+0:?     'iimg2Drgba' (layout(rgba32i ) uniform iimage2D)
+0:?     'img2Drgba' (layout(rgba32f ) uniform image2D)
+0:?     'uimg2D' (layout(r32ui ) uniform uimage2D)
+0:?     'img2DMS' (uniform image2DMS)
+0:?     'img2DMSWO' (writeonly uniform image2DMS)
+0:?     'vol' (volatile float)
+0:?     'vol2' (readonly int)
+0:?     'qualim1' (layout(r32i ) coherent readonly uniform iimage2D)
+0:?     'qualim2' (layout(r32i ) coherent restrict readonly uniform iimage2D)
+0:?     'i1bad' (layout(rg8i ) uniform uimage2D)
+0:?     'i2bad' (layout(rgba32i ) uniform image2D)
+0:?     'i3bad' (layout(rgba32f ) uniform uimage2D)
+0:?     'i4bad' (layout(r8_snorm ) uniform iimage2D)
+0:?     'i5bad' (layout(rgba32ui ) uniform iimage2D)
+0:?     'i6bad' (layout(r8ui ) uniform iimage2D)
 0:?     'gl_VertexID' (gl_VertexId int)
 0:?     'gl_InstanceID' (gl_InstanceId int)
 
@@ -223,7 +330,7 @@ ERROR: node is still EOpNull!
 0:42        No loop body
 0:50  Function Definition: bar(vf4; (void)
 0:50    Function Parameters: 
-0:50      'v' (in 4-component vector of float)
+0:50      'v' (volatile in 4-component vector of float)
 0:?     Sequence
 0:53      's' (int)
 0:54      's' (int)
@@ -296,6 +403,84 @@ ERROR: node is still EOpNull!
 0:97          'a' (int)
 0:97          Constant:
 0:97            -1 (const int)
+0:109  Function Definition: qux( (void)
+0:109    Function Parameters: 
+0:111    Sequence
+0:111      Sequence
+0:111        move second child to first child (int)
+0:111          'i' (int)
+0:111          aoeu: direct index for structure (layout(column_major shared ) uniform int)
+0:111            'anon@0' (layout(binding=7 column_major shared ) uniform block{layout(column_major shared ) uniform int aoeu})
+0:111            Constant:
+0:111              0 (const uint)
+0:112      Function Call: imageAtomicCompSwap(iI21;vi2;i1;i1; (int)
+0:112        'iimg2D' (layout(r32i ) uniform iimage2D)
+0:112        Construct ivec2 (2-component vector of int)
+0:112          'i' (int)
+0:112          'i' (int)
+0:112        'i' (int)
+0:112        'i' (int)
+0:113      Function Call: imageAtomicAdd(uI21;vi2;u1; (uint)
+0:113        'uimg2D' (layout(r32ui ) uniform uimage2D)
+0:113        Construct ivec2 (2-component vector of int)
+0:113          'i' (int)
+0:113          'i' (int)
+0:113        Convert int to uint (uint)
+0:113          'i' (int)
+0:114      Function Call: imageAtomicMin(iI21;vi2;i1; (int)
+0:114        'iimg2Drgba' (layout(rgba32i ) uniform iimage2D)
+0:114        Construct ivec2 (2-component vector of int)
+0:114          'i' (int)
+0:114          'i' (int)
+0:114        'i' (int)
+0:115      Constant:
+0:115        0.000000
+0:116      Sequence
+0:116        move second child to first child (4-component vector of int)
+0:116          'pos' (4-component vector of int)
+0:116          Function Call: imageLoad(iI21;vi2; (4-component vector of int)
+0:116            'iimg2D' (layout(r32i ) uniform iimage2D)
+0:116            Construct ivec2 (2-component vector of int)
+0:116              'i' (int)
+0:116              'i' (int)
+0:117      Sequence
+0:117        move second child to first child (4-component vector of float)
+0:117          'col' (4-component vector of float)
+0:117          Function Call: imageLoad(I21;vi2;i1; (4-component vector of float)
+0:117            'img2DMS' (uniform image2DMS)
+0:117            Construct ivec2 (2-component vector of int)
+0:117              'i' (int)
+0:117              'i' (int)
+0:117            'i' (int)
+0:118      Function Call: imageStore(I21;vi2;i1;vf4; (void)
+0:118        'img2DMSWO' (writeonly uniform image2DMS)
+0:118        Construct ivec2 (2-component vector of int)
+0:118          'i' (int)
+0:118          'i' (int)
+0:118        'i' (int)
+0:118        Constant:
+0:118          0.000000
+0:118          0.000000
+0:118          0.000000
+0:118          0.000000
+0:119      Function Call: imageLoad(I21;vi2;i1; (4-component vector of float)
+0:119        'img2DMSWO' (writeonly uniform image2DMS)
+0:119        Construct ivec2 (2-component vector of int)
+0:119          'i' (int)
+0:119          'i' (int)
+0:119        'i' (int)
+0:125  Function Definition: passr(iI21; (void)
+0:125    Function Parameters: 
+0:125      'image' (coherent readonly in iimage2D)
+0:132  Function Definition: passrc( (void)
+0:132    Function Parameters: 
+0:134    Sequence
+0:134      Function Call: passr(iI21; (void)
+0:134        'qualim1' (layout(r32i ) coherent readonly uniform iimage2D)
+0:135      Function Call: passr(iI21; (void)
+0:135        'qualim2' (layout(r32i ) coherent restrict readonly uniform iimage2D)
+0:136      Function Call: passr(iI21; (void)
+0:136        'iimg2D' (layout(r32i ) uniform iimage2D)
 0:?   Linker Objects
 0:?     'v2' (smooth out 2-component vector of float)
 0:?     'bad' (in 10-element array of 4-component vector of float)
@@ -330,6 +515,22 @@ ERROR: node is still EOpNull!
 0:?     'patchOut' (smooth patch out 4-component vector of float)
 0:?     'comma0' (int)
 0:?     'comma1' (1-element array of int)
+0:?     'iimg2D' (layout(r32i ) uniform iimage2D)
+0:?     'iimg2Drgba' (layout(rgba32i ) uniform iimage2D)
+0:?     'img2Drgba' (layout(rgba32f ) uniform image2D)
+0:?     'uimg2D' (layout(r32ui ) uniform uimage2D)
+0:?     'img2DMS' (uniform image2DMS)
+0:?     'img2DMSWO' (writeonly uniform image2DMS)
+0:?     'vol' (volatile float)
+0:?     'vol2' (readonly int)
+0:?     'qualim1' (layout(r32i ) coherent readonly uniform iimage2D)
+0:?     'qualim2' (layout(r32i ) coherent restrict readonly uniform iimage2D)
+0:?     'i1bad' (layout(rg8i ) uniform uimage2D)
+0:?     'i2bad' (layout(rgba32i ) uniform image2D)
+0:?     'i3bad' (layout(rgba32f ) uniform uimage2D)
+0:?     'i4bad' (layout(r8_snorm ) uniform iimage2D)
+0:?     'i5bad' (layout(rgba32ui ) uniform iimage2D)
+0:?     'i6bad' (layout(r8ui ) uniform iimage2D)
 0:?     'gl_VertexID' (gl_VertexId int)
 0:?     'gl_InstanceID' (gl_InstanceId int)
 
diff --git a/Test/baseResults/430.vert.out b/Test/baseResults/430.vert.out
index 2706e88342720b5436dea7b62aef9dd11cfb0211..641bab20f649f2c969deee8b694267333e5fcd48 100644
--- a/Test/baseResults/430.vert.out
+++ b/Test/baseResults/430.vert.out
@@ -67,7 +67,7 @@ ERROR: node is still EOpNull!
 0:31  Function Definition: foo3(vf4;vf3;vf2;vf3; (void)
 0:31    Function Parameters: 
 0:31      'v4' (in 4-component vector of float)
-0:31      'v3' (in 3-component vector of float)
+0:31      'v3' (volatile in 3-component vector of float)
 0:31      'v2' (in 2-component vector of float)
 0:31      'cv3' (in 3-component vector of float)
 0:?   Linker Objects
@@ -139,7 +139,7 @@ ERROR: node is still EOpNull!
 0:31  Function Definition: foo3(vf4;vf3;vf2;vf3; (void)
 0:31    Function Parameters: 
 0:31      'v4' (in 4-component vector of float)
-0:31      'v3' (in 3-component vector of float)
+0:31      'v3' (volatile in 3-component vector of float)
 0:31      'v2' (in 2-component vector of float)
 0:31      'cv3' (in 3-component vector of float)
 0:?   Linker Objects
diff --git a/Test/baseResults/specExamples.frag.out b/Test/baseResults/specExamples.frag.out
index 3d1ef00786bbc31e84e2038d87b1c8e471ad5393..d4438e8b38716597639de0850fd4aa7a5de2a332 100644
--- a/Test/baseResults/specExamples.frag.out
+++ b/Test/baseResults/specExamples.frag.out
@@ -10,18 +10,17 @@ ERROR: 0:75: 'Atten' : member storage qualifier cannot contradict block storage
 ERROR: 0:87: 'Color' : redefinition 
 ERROR: 0:92: 'redeclaration' : cannot redeclare with different qualification: gl_FragCoord
 ERROR: 0:93: 'redeclaration' : cannot redeclare with different qualification: gl_FragCoord
-ERROR: 0:96: 'early_fragment_tests' : unrecognized layout identifier, or qualifier requires assignemnt (e.g., binding = 4) 
 ERROR: 0:99: 'local_size_x' : there is no such layout identifier for this stage taking an assigned value 
 ERROR: 0:99: 'local_size_y' : there is no such layout identifier for this stage taking an assigned value 
 ERROR: 0:100: 'local_size_x' : there is no such layout identifier for this stage taking an assigned value 
 ERROR: 0:102: 'color' : redefinition 
 ERROR: 0:103: 'index' : there is no such layout identifier for this stage taking an assigned value 
 ERROR: 0:104: 'location' : overlapping use of location 3
-ERROR: 0:106: 'depth_greater' : unrecognized layout identifier, or qualifier requires assignemnt (e.g., binding = 4) 
-ERROR: 0:112: 'depth_any' : unrecognized layout identifier, or qualifier requires assignemnt (e.g., binding = 4) 
-ERROR: 0:115: 'depth_greater' : unrecognized layout identifier, or qualifier requires assignemnt (e.g., binding = 4) 
-ERROR: 0:118: 'depth_less' : unrecognized layout identifier, or qualifier requires assignemnt (e.g., binding = 4) 
-ERROR: 0:121: 'depth_unchanged' : unrecognized layout identifier, or qualifier requires assignemnt (e.g., binding = 4) 
+ERROR: 0:106: 'depth_greater' : unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4) 
+ERROR: 0:112: 'depth_any' : unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4) 
+ERROR: 0:115: 'depth_greater' : unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4) 
+ERROR: 0:118: 'depth_less' : unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4) 
+ERROR: 0:121: 'depth_unchanged' : unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4) 
 ERROR: 0:150: 'constructor' : constructing from a non-dereferenced array 
 ERROR: 0:150: '=' :  cannot convert from 'const float' to '3-element array of 4-component vector of float'
 ERROR: 0:152: 'constructor' :  cannot convert parameter 1 from 'const 2-element array of 4-component vector of float' to '4-component vector of float'
@@ -46,13 +45,14 @@ ERROR: 0:226: 'in' : not allowed in nested scope
 ERROR: 0:227: 'in' : not allowed in nested scope 
 ERROR: 0:228: 'in' : not allowed in nested scope 
 ERROR: 0:232: 'out' : not allowed in nested scope 
-ERROR: 46 compilation errors.  No code generated.
+ERROR: 45 compilation errors.  No code generated.
 
 
 Shader version: 430
 Requested GL_3DL_array_objects
 gl_FragCoord pixel center is integer
 gl_FragCoord origin is upper left
+using early_fragment_tests
 ERROR: node is still EOpNull!
 0:5  Sequence
 0:5    move second child to first child (int)
@@ -305,6 +305,7 @@ Shader version: 430
 Requested GL_3DL_array_objects
 gl_FragCoord pixel center is integer
 gl_FragCoord origin is upper left
+using early_fragment_tests
 ERROR: node is still EOpNull!
 0:5  Sequence
 0:5    move second child to first child (int)
diff --git a/Test/baseResults/specExamples.vert.out b/Test/baseResults/specExamples.vert.out
index 95c412602fa304dd624fbec9221fc11b1e3ebff7..3b20d8fb984fbe5ed6cbebca1b571124eae89d75 100644
--- a/Test/baseResults/specExamples.vert.out
+++ b/Test/baseResults/specExamples.vert.out
@@ -2,13 +2,13 @@ specExamples.vert
 Warning, version 430 is not yet complete; most version-specific features are present, but some are missing.
 ERROR: 0:23: 'transforms' : redeclaration of array with size 
 ERROR: 0:29: 'location' : can only appy to uniform, buffer, in, or out storage qualifiers 
-ERROR: 0:31: 'triangles' : unrecognized layout identifier, or qualifier requires assignemnt (e.g., binding = 4) 
+ERROR: 0:31: 'triangles' : unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4) 
 ERROR: 0:31: 'invocations' : there is no such layout identifier for this stage taking an assigned value 
-ERROR: 0:33: 'lines' : unrecognized layout identifier, or qualifier requires assignemnt (e.g., binding = 4) 
-ERROR: 0:35: 'triangle_strip' : unrecognized layout identifier, or qualifier requires assignemnt (e.g., binding = 4) 
+ERROR: 0:33: 'lines' : unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4) 
+ERROR: 0:35: 'triangle_strip' : unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4) 
 ERROR: 0:35: 'max_vertices' : there is no such layout identifier for this stage taking an assigned value 
 ERROR: 0:36: 'max_vertices' : there is no such layout identifier for this stage taking an assigned value 
-ERROR: 0:37: 'triangle_strip' : unrecognized layout identifier, or qualifier requires assignemnt (e.g., binding = 4) 
+ERROR: 0:37: 'triangle_strip' : unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4) 
 ERROR: 0:41: 'stream' : there is no such layout identifier for this stage taking an assigned value 
 ERROR: 0:43: 'stream' : there is no such layout identifier for this stage taking an assigned value 
 ERROR: 0:45: 'stream' : there is no such layout identifier for this stage taking an assigned value 
@@ -35,16 +35,20 @@ ERROR: 0:106: '' : vertex input cannot be further qualified
 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:132: '' : memory qualifiers can only be used on image types 
 ERROR: 0:134: '' : function does not return a value: funcA
 ERROR: 0:136: '' : function does not return a value: funcB
-ERROR: 0:137: 'rgba32f' : unrecognized layout identifier, or qualifier requires assignemnt (e.g., binding = 4) 
-ERROR: 0:138: 'rgba32f' : unrecognized layout identifier, or qualifier requires assignemnt (e.g., binding = 4) 
 ERROR: 0:153: '' : function does not return a value: func3
+ERROR: 0:170: 'coherent' : argument cannot drop memory qualifier when passed to formal parameter 
 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: 42 compilation errors.  No code generated.
+ERROR: 46 compilation errors.  No code generated.
 
 
 Shader version: 430
@@ -52,7 +56,7 @@ Requested GL_3DL_array_objects
 ERROR: node is still EOpNull!
 0:134  Function Definition: funcA(I21; (4-component vector of float)
 0:134    Function Parameters: 
-0:134      'a' (in image2D)
+0:134      'a' (restrict in image2D)
 0:136  Function Definition: funcB(I21; (4-component vector of float)
 0:136    Function Parameters: 
 0:136      'a' (in image2D)
@@ -225,9 +229,9 @@ ERROR: node is still EOpNull!
 0:167          Constant:
 0:167            0 (const int)
 0:169      Function Call: funcA(I21; (4-component vector of float)
-0:169        'img1' (uniform image2D)
+0:169        'img1' (layout(rgba32f ) uniform image2D)
 0:170      Function Call: funcB(I21; (4-component vector of float)
-0:170        'img2' (coherent uniform image2D)
+0:170        'img2' (layout(rgba32f ) coherent uniform image2D)
 0:?       Sequence
 0:178        Sequence
 0:178          move second child to first child (structure{float intensity, 3-component vector of float position})
@@ -314,8 +318,8 @@ ERROR: node is still EOpNull!
 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:?     'shv' (shared 4-component vector of float)
-0:?     'img1' (uniform image2D)
-0:?     'img2' (coherent uniform image2D)
+0:?     'img1' (layout(rgba32f ) uniform image2D)
+0:?     'img2' (layout(rgba32f ) coherent uniform image2D)
 0:?     'gl_VertexID' (gl_VertexId int)
 0:?     'gl_InstanceID' (gl_InstanceId int)
 
@@ -328,7 +332,7 @@ Requested GL_3DL_array_objects
 ERROR: node is still EOpNull!
 0:134  Function Definition: funcA(I21; (4-component vector of float)
 0:134    Function Parameters: 
-0:134      'a' (in image2D)
+0:134      'a' (restrict in image2D)
 0:136  Function Definition: funcB(I21; (4-component vector of float)
 0:136    Function Parameters: 
 0:136      'a' (in image2D)
@@ -501,9 +505,9 @@ ERROR: node is still EOpNull!
 0:167          Constant:
 0:167            0 (const int)
 0:169      Function Call: funcA(I21; (4-component vector of float)
-0:169        'img1' (uniform image2D)
+0:169        'img1' (layout(rgba32f ) uniform image2D)
 0:170      Function Call: funcB(I21; (4-component vector of float)
-0:170        'img2' (coherent uniform image2D)
+0:170        'img2' (layout(rgba32f ) coherent uniform image2D)
 0:?       Sequence
 0:178        Sequence
 0:178          move second child to first child (structure{float intensity, 3-component vector of float position})
@@ -590,8 +594,8 @@ ERROR: node is still EOpNull!
 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:?     'shv' (shared 4-component vector of float)
-0:?     'img1' (uniform image2D)
-0:?     'img2' (coherent uniform image2D)
+0:?     'img1' (layout(rgba32f ) uniform image2D)
+0:?     'img2' (layout(rgba32f ) coherent uniform image2D)
 0:?     'gl_VertexID' (gl_VertexId int)
 0:?     'gl_InstanceID' (gl_InstanceId int)
 
diff --git a/Test/baseResults/test.conf b/Test/baseResults/test.conf
index 8fc933656813616d71950b9c437eac5aa1f010fc..bcdeed02c29c66375c159dfa7f678bc8737e157f 100644
--- a/Test/baseResults/test.conf
+++ b/Test/baseResults/test.conf
@@ -36,6 +36,7 @@ MaxGeometryOutputComponents 128
 MaxFragmentInputComponents 128
 MaxImageUnits 8
 MaxCombinedImageUnitsAndFragmentOutputs 8
+MaxCombinedShaderOutputResources 8
 MaxImageSamples 0
 MaxVertexImageUniforms 0
 MaxTessControlImageUniforms 0
diff --git a/Test/reflection.vert b/Test/reflection.vert
index c08ea26ab620557f610a3f1c29325830b3cc359c..101f5ffc532fb25b651e90f5dd1a5f0d52c1f17f 100644
--- a/Test/reflection.vert
+++ b/Test/reflection.vert
@@ -72,7 +72,7 @@ uniform float uf2;
 uniform float ufDead3;
 uniform float ufDead4;
 
-uniform uimage2D image_ui2D;
+uniform writeonly uimage2D image_ui2D;
 uniform sampler2D sampler_2D;
 uniform sampler2DMSArray sampler_2DMSArray;
 
@@ -111,7 +111,7 @@ void liveFunction2()
     float f = uf1;
 }
 
-void liveFunction1(uimage2D p_ui2D, sampler2D p_2D, sampler2DMSArray p_2DMSArray)
+void liveFunction1(writeonly uimage2D p_ui2D, sampler2D p_2D, sampler2DMSArray p_2DMSArray)
 
 {
     liveFunction2();
diff --git a/Todo.txt b/Todo.txt
index afd370a6fe75dd4e512da6eb8694c80c4e90315c..c4e1a701b53979e7b5fe445b55a1cb9ea66baa0d 100644
--- a/Todo.txt
+++ b/Todo.txt
@@ -168,11 +168,12 @@ Shader Functionality to Implement/Finish
       + ES convergence
         + Clarify that .xyzwxy.xy is illegal, as it temporarily makes a “vec6”.
         + Clarify that return statements only accept values (no return of a void function).
-      - Add image types (GL_ARB_shader_image_load_store)
+      + Add image types (GL_ARB_shader_image_load_store)
         + 33 new types, all with “image” in their name, correspond to the non-shadow texture types
-        + addition of memory qualifiers: coherent,volatile, restrict, readonly, and writeonly
-        - can read/write/modify images from a shader, through new built-in functions
-        - qualifiers can act independently on the opaque shader variable and the backing image, so extra qualifiers can be used to separately qualify these
+        + addition of memory qualifiers: coherent, volatile, restrict, readonly, and writeonly
+        + can read/write/modify images from a shader, through new built-in functions
+        + qualifiers can act independently on the opaque shader variable and the backing image, so extra qualifiers can be used to separately qualify these
+        + early_fragment_tests
       + Variables declared in if and else statements are scoped only to the end of those statements, especially for non-compound statements
         Note, this is not backward compatible, it may depend on #version.
       + Allow implicit conversions of return values to the declared type of the function.
diff --git a/glslang/Include/ResourceLimits.h b/glslang/Include/ResourceLimits.h
index 03a39fd1d061d9fcdd00499467488e1ed3892aa9..bdf879c5ed7c734c2fec5890a94bbf6748d8c78c 100644
--- a/glslang/Include/ResourceLimits.h
+++ b/glslang/Include/ResourceLimits.h
@@ -88,6 +88,7 @@ struct TBuiltInResource {
     int maxFragmentInputComponents;
     int maxImageUnits;
     int maxCombinedImageUnitsAndFragmentOutputs;
+    int maxCombinedShaderOutputResources;
     int maxImageSamples;
     int maxVertexImageUniforms;
     int maxTessControlImageUniforms;
diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h
index 9ab22ebbac25d94db4b41a21e627201f1b629e19..ef1dcd9e6ca08f6384aa39cdd54a79969069571a 100644
--- a/glslang/Include/Types.h
+++ b/glslang/Include/Types.h
@@ -241,6 +241,61 @@ enum TVertexOrder {
     EvoCcw
 };
 
+// Note: order matters, as type of format is done by comparison.
+enum TLayoutFormat {
+    ElfNone,
+
+    // Float image
+    ElfRgba32f,
+    ElfRgba16f,
+    ElfRg32f,
+    ElfRg16f,
+    ElfR11fG11fB10f,
+    ElfR32f,
+    ElfR16f,
+    ElfRgba16,
+    ElfRgb10A2,
+    ElfRgba8,
+    ElfRg16,
+    ElfRg8,
+    ElfR16,
+    ElfR8,
+    ElfRgba16Snorm,
+    ElfRgba8Snorm,
+    ElfRg16Snorm,
+    ElfRg8Snorm,
+    ElfR16Snorm,
+    ElfR8Snorm,
+
+    ElfFloatGuard,      // to help with comparisons
+
+    // Int image
+    ElfRgba32i,
+    ElfRgba16i,
+    ElfRgba8i,
+    ElfRg32i,
+    ElfRg16i,
+    ElfRg8i,
+    ElfR32i,
+    ElfR16i,
+    ElfR8i,
+
+    ElfIntGuard,       // to help with comparisons
+
+    // Uint image
+    ElfRgba32ui,
+    ElfRgba16ui,
+    ElfRgba8ui,
+    ElfRg32ui,
+    ElfRg16ui,
+    ElfRg8ui,
+    ElfR32ui,
+    ElfR16ui,
+    ElfR8ui,
+
+    ElfCount
+};
+
 class TQualifier {
 public:
     void clear()
@@ -416,6 +471,8 @@ public:
         layoutXfbBuffer = layoutXfbBufferEnd;
         layoutXfbStride = layoutXfbStrideEnd;
         layoutXfbOffset = layoutXfbOffsetEnd;
+
+        layoutFormat = ElfNone;
     }
     bool hasLayout() const
     {
@@ -423,7 +480,8 @@ public:
                hasLocation() ||
                hasBinding() ||
                hasStream() ||
-               hasXfb();
+               hasXfb() ||
+               hasFormat();
     }
     TLayoutMatrix  layoutMatrix  : 3;
     TLayoutPacking layoutPacking : 4;
@@ -451,6 +509,8 @@ public:
                  unsigned int layoutXfbOffset       : 10;
     static const unsigned int layoutXfbOffsetEnd = 0x3FF;
 
+    TLayoutFormat layoutFormat                      :  8;
+
     bool hasUniformLayout() const
     {
         return hasMatrix() ||
@@ -491,6 +551,10 @@ public:
     {
         return layoutStream != layoutStreamEnd;
     }
+    bool hasFormat() const
+    {
+        return layoutFormat != ElfNone;
+    }
     bool hasXfb() const
     {
         return hasXfbBuffer() ||
@@ -527,12 +591,58 @@ public:
         default:             return "none";
         }
     }
+    static const char* getLayoutFormatString(TLayoutFormat f)
+    {
+        switch (f) {
+        case ElfRgba32f:      return "rgba32f";
+        case ElfRgba16f:      return "rgba16f";
+        case ElfRg32f:        return "rg32f";
+        case ElfRg16f:        return "rg16f";
+        case ElfR11fG11fB10f: return "r11f_g11f_b10f";
+        case ElfR32f:         return "r32f";
+        case ElfR16f:         return "r16f";
+        case ElfRgba16:       return "rgba16";
+        case ElfRgb10A2:      return "rgb10_a2";
+        case ElfRgba8:        return "rgba8";
+        case ElfRg16:         return "rg16";
+        case ElfRg8:          return "rg8";
+        case ElfR16:          return "r16";
+        case ElfR8:           return "r8";
+        case ElfRgba16Snorm:  return "rgba16_snorm";
+        case ElfRgba8Snorm:   return "rgba8_snorm";
+        case ElfRg16Snorm:    return "rg16_snorm";
+        case ElfRg8Snorm:     return "rg8_snorm";
+        case ElfR16Snorm:     return "r16_snorm";
+        case ElfR8Snorm:      return "r8_snorm";
+
+        case ElfRgba32i:      return "rgba32i";
+        case ElfRgba16i:      return "rgba16i";
+        case ElfRgba8i:       return "rgba8i";
+        case ElfRg32i:        return "rg32i";
+        case ElfRg16i:        return "rg16i";
+        case ElfRg8i:         return "rg8i";
+        case ElfR32i:         return "r32i";
+        case ElfR16i:         return "r16i";
+        case ElfR8i:          return "r8i";
+
+        case ElfRgba32ui:     return "rgba32ui";
+        case ElfRgba16ui:     return "rgba16ui";
+        case ElfRgba8ui:      return "rgba8ui";
+        case ElfRg32ui:       return "rg32ui";
+        case ElfRg16ui:       return "rg16ui";
+        case ElfRg8ui:        return "rg8ui";
+        case ElfR32ui:        return "r32ui";
+        case ElfR16ui:        return "r16ui";
+        case ElfR8ui:         return "r8ui";
+        default:              return "none";
+        }
+    }
     static const char* getGeometryString(TLayoutGeometry geometry)
     {
         switch (geometry) {
         case ElgPoints:             return "points";
         case ElgLines:              return "lines";
-        case ElgLinesAdjacency:     return "lines_adjancency";
+        case ElgLinesAdjacency:     return "lines_adjacency";
         case ElgLineStrip:          return "line_strip";
         case ElgTriangles:          return "triangles";
         case ElgTrianglesAdjacency: return "triangles_adjacency";
@@ -583,6 +693,7 @@ struct TShaderQualifiers {
     TVertexSpacing spacing;
     TVertexOrder order;
     bool pointMode;
+    bool earlyFragmentTests;  // fragment input
 
     void init()
     {
@@ -594,6 +705,7 @@ struct TShaderQualifiers {
         spacing = EvsNone;
         order = EvoNone;
         pointMode = false;
+        earlyFragmentTests = false;
     }
 
     // Merge in characteristics from the 'src' qualifier.  They can override when
@@ -616,6 +728,8 @@ struct TShaderQualifiers {
             order = src.order;
         if (src.pointMode)
             pointMode = true;
+        if (src.earlyFragmentTests)
+            earlyFragmentTests = true;
     }
 };
 
@@ -1023,6 +1137,9 @@ public:
                 if (qualifier.hasAlign())
                     p += snprintf(p, end - p, "align=%d ", qualifier.layoutAlign);
 
+                if (qualifier.hasFormat())
+                    p += snprintf(p, end - p, "%s ", TQualifier::getLayoutFormatString(qualifier.layoutFormat));
+
                 if (qualifier.hasXfbBuffer() && qualifier.hasXfbOffset())
                     p += snprintf(p, end - p, "xfb_buffer=%d ", qualifier.layoutXfbBuffer);
                 if (qualifier.hasXfbOffset())
diff --git a/glslang/MachineIndependent/Initialize.cpp b/glslang/MachineIndependent/Initialize.cpp
index 9fa6e4c4e14b9adbc194038b4a392b83e5db118b..4ea7c965b0853306e90a015b8c624dff2ddbb740 100644
--- a/glslang/MachineIndependent/Initialize.cpp
+++ b/glslang/MachineIndependent/Initialize.cpp
@@ -845,7 +845,7 @@ void TBuiltIns::initialize(int version, EProfile profile)
                 "void barrier();"
                 );
 
-        if (version >= 420)
+        if (version >= 130)
             commonBuiltins.append(
                 "void memoryBarrier();"
                 );
@@ -1467,9 +1467,6 @@ void TBuiltIns::add2ndGenerationSamplingImaging(int version, EProfile profile)
     // enumerate all the types
     for (int image = 0; image <= 1; ++image) { // loop over "bool" image vs sampler
 
-        if (image > 0 && version < 420)
-            continue;
-
         for (int shadow = 0; shadow <= 1; ++shadow) { // loop over "bool" shadow or not
             for (int ms = 0; ms <=1; ++ms) {
 
@@ -1523,8 +1520,7 @@ void TBuiltIns::add2ndGenerationSamplingImaging(int version, EProfile profile)
                                 addImageFunctions(sampler, typeName, version, profile);
                             else {
                                 addSamplingFunctions(sampler, typeName, version, profile);
-                                if (version >= 130)
-                                    addGatherFunctions(sampler, typeName, version, profile);
+                                addGatherFunctions(sampler, typeName, version, profile);
                             }
                         }
                     }
@@ -1577,7 +1573,63 @@ void TBuiltIns::addQueryFunctions(TSampler sampler, TString& typeName, int versi
 //
 void TBuiltIns::addImageFunctions(TSampler sampler, TString& typeName, int version, EProfile profile)
 {
-    // TODO: 4.2 Functionality: imaging functions
+    int dims = dimMap[sampler.dim] + (sampler.arrayed ? 1 : 0);
+    TString imageParams = typeName;
+    if (dims == 1)
+        imageParams.append(", int");
+    else {
+        imageParams.append(", ivec");
+        imageParams.append(postfixes[dims]);
+    }
+    if (sampler.ms)
+        imageParams.append(", int");
+
+    commonBuiltins.append(prefixes[sampler.type]);
+    commonBuiltins.append("vec4 imageLoad(readonly ");
+    commonBuiltins.append(imageParams);
+    commonBuiltins.append(");\n");
+
+    commonBuiltins.append("void imageStore(writeonly ");
+    commonBuiltins.append(imageParams);
+    commonBuiltins.append(", ");
+    commonBuiltins.append(prefixes[sampler.type]);
+    commonBuiltins.append("vec4);\n");
+
+    if (sampler.type == EbtInt || sampler.type == EbtUint) {
+        const char* dataType = sampler.type == EbtInt ? "int" : "uint";
+
+        const int numBuiltins = 7;
+
+        static const char* atomicFunc[numBuiltins] = {
+            " imageAtomicAdd(",
+            " imageAtomicMin(",
+            " imageAtomicMax(",
+            " imageAtomicAnd(",
+            " imageAtomicOr(",
+            " imageAtomicXor(",
+            " imageAtomicExchange("
+        }; 
+
+        for (size_t i = 0; i < numBuiltins; ++i) {
+            commonBuiltins.append(dataType);
+            commonBuiltins.append(atomicFunc[i]);
+            if (version >= 450)
+                commonBuiltins.append("coherent ");
+            commonBuiltins.append(imageParams);
+            commonBuiltins.append(", ");
+            commonBuiltins.append(dataType);
+            commonBuiltins.append(");\n");
+        }
+
+        commonBuiltins.append(dataType);
+        commonBuiltins.append(" imageAtomicCompSwap(");
+        commonBuiltins.append(imageParams);
+        commonBuiltins.append(", ");
+        commonBuiltins.append(dataType);
+        commonBuiltins.append(", ");
+        commonBuiltins.append(dataType);
+        commonBuiltins.append(");\n");
+    }
 }
 
 //
@@ -2111,17 +2163,27 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf
         }
 
         // images
-        if (version >= 420) {
-            //snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryImageUniforms = %d;", resources.);
-            //snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryTextureImageUnits = %d;", resources.);
-            //snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlImageUniforms = %d;", resources.);
-            //snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationImageUniforms = %d;", resources.);
-            //snprintf(builtInConstant, maxSize, "const int gl_MaxImageUnits = %d;", resources.);
-            //snprintf(builtInConstant, maxSize, "const int gl_MaxCombinedImageUnitsAndFragmentOutputs = %d;", resources.);
-            //snprintf(builtInConstant, maxSize, "const int gl_MaxImageSamples = %d;", resources.);
-            //snprintf(builtInConstant, maxSize, "const int gl_MaxVertexImageUniforms = %d;", resources.);
-            //snprintf(builtInConstant, maxSize, "const int gl_MaxFragmentImageUniforms = %d;", resources.);
-            //snprintf(builtInConstant, maxSize, "const int gl_MaxCombinedImageUniforms = %d;", resources.);
+        if (version >= 130) {
+            snprintf(builtInConstant, maxSize, "const int gl_MaxImageUnits = %d;", resources.maxImageUnits);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxCombinedImageUnitsAndFragmentOutputs = %d;", resources.maxCombinedImageUnitsAndFragmentOutputs);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxCombinedShaderOutputResources = %d;", resources.maxCombinedShaderOutputResources);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxImageSamples = %d;", resources.maxImageSamples);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxVertexImageUniforms = %d;", resources.maxVertexImageUniforms);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessControlImageUniforms = %d;", resources.maxTessControlImageUniforms);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxTessEvaluationImageUniforms = %d;", resources.maxTessEvaluationImageUniforms);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxGeometryImageUniforms = %d;", resources.maxGeometryImageUniforms);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxFragmentImageUniforms = %d;", resources.maxFragmentImageUniforms);
+            s.append(builtInConstant);
+            snprintf(builtInConstant, maxSize, "const int gl_MaxCombinedImageUniforms = %d;", resources.maxCombinedImageUniforms);
+            s.append(builtInConstant);
         }
 
         // compute
@@ -2264,6 +2326,11 @@ void IdentifyBuiltIns(int version, EProfile profile, EShLanguage language, TSymb
             symbolTable.setFunctionExtensions("textureCubeGradEXT",   1, &GL_EXT_shader_texture_lod);
         }
 
+        // GL_ARB_shader_image_load_store
+        if (version < 420)
+            symbolTable.setFunctionExtensions("memoryBarrier", 1, &GL_ARB_shader_image_load_store);
+        // All the image access functions are protected by checks on the type of the first argument.
+
         symbolTable.setVariableExtensions("gl_FragDepthEXT", 1, &GL_EXT_frag_depth);
         break;
 
diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp
index e950eff851fdec8da6b6f722c73cb545cb8ba42b..61874029465876da06a24f67c68b8a4e38766abc 100644
--- a/glslang/MachineIndependent/ParseHelper.cpp
+++ b/glslang/MachineIndependent/ParseHelper.cpp
@@ -967,18 +967,32 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* funct
                 requireExtensions(loc, fnCandidate->getNumExtensions(), fnCandidate->getExtensions(), fnCandidate->getName().c_str());
 
             if (arguments) {
-                // Make sure storage qualifications work for these arguments.
+                // Make sure qualifications work for these arguments.
                 TIntermAggregate* aggregate = arguments->getAsAggregate();
                 for (int i = 0; i < fnCandidate->getParamCount(); ++i) {
-                    TStorageQualifier qual = (*fnCandidate)[i].type->getQualifier().storage;
-                    if (qual == EvqOut || qual == EvqInOut) {
-                        // At this early point there is a slight ambiguity between whether an aggregate 'arguments'
-                        // is the single argument itself or its children are the arguments.  Only one argument
-                        // means take 'arguments' itself as the one argument.
-                        TIntermNode* arg = fnCandidate->getParamCount() == 1 ? arguments : (aggregate ? aggregate->getSequence()[i] : arguments);
+                    // At this early point there is a slight ambiguity between whether an aggregate 'arguments'
+                    // is the single argument itself or its children are the arguments.  Only one argument
+                    // means take 'arguments' itself as the one argument.
+                    TIntermNode* arg = fnCandidate->getParamCount() == 1 ? arguments : (aggregate ? aggregate->getSequence()[i] : arguments);
+                    TQualifier& formalQualifier = (*fnCandidate)[i].type->getQualifier();
+                    if (formalQualifier.storage == EvqOut || formalQualifier.storage == EvqInOut) {
                         if (lValueErrorCheck(arguments->getLoc(), "assign", arg->getAsTyped()))
                             error(arguments->getLoc(), "Non-L-value cannot be passed for 'out' or 'inout' parameters.", "out", "");
                     }
+                    TQualifier& argQualifier = arg->getAsTyped()->getQualifier();
+                    if (argQualifier.isMemory()) {
+                        const char* message = "argument cannot drop memory qualifier when passed to formal parameter";
+                        if (argQualifier.volatil && ! formalQualifier.volatil)
+                            error(arguments->getLoc(), message, "volatile", "");
+                        if (argQualifier.coherent && ! formalQualifier.coherent)
+                            error(arguments->getLoc(), message, "coherent", "");
+                        if (argQualifier.restrict && ! formalQualifier.restrict)
+                            error(arguments->getLoc(), message, "restrict", "");
+                        if (argQualifier.readonly && ! formalQualifier.readonly)
+                            error(arguments->getLoc(), message, "readonly", "");
+                        if (argQualifier.writeonly && ! formalQualifier.writeonly)
+                            error(arguments->getLoc(), message, "writeonly", "");
+                    }
                 }
 
                 // Convert 'in' arguments
@@ -1273,6 +1287,14 @@ void TParseContext::nonOpBuiltInCheck(TSourceLoc loc, const TFunction& fnCandida
             }
         }
     }
+    if (fnCandidate.getName().compare(0, 11, "imageAtomic") == 0) {
+        const TType& imageType = callNode.getSequence()[0]->getAsTyped()->getType();
+        if (imageType.getSampler().type == EbtInt || imageType.getSampler().type == EbtUint) {
+            if (imageType.getQualifier().layoutFormat != ElfR32i && imageType.getQualifier().layoutFormat != ElfR32ui)
+                error(loc, "only supported on image with format r32i or r32ui", fnCandidate.getName().c_str(), "");
+        } else
+            error(loc, "only supported on integer images", fnCandidate.getName().c_str(), "");
+    }
 }
 
 //
@@ -2651,6 +2673,13 @@ void TParseContext::paramCheckFix(TSourceLoc loc, const TStorageQualifier& quali
 
 void TParseContext::paramCheckFix(TSourceLoc loc, const TQualifier& qualifier, TType& type)
 {
+    if (qualifier.isMemory()) {
+        type.getQualifier().volatil   = qualifier.volatil;
+        type.getQualifier().coherent  = qualifier.coherent;
+        type.getQualifier().readonly  = qualifier.readonly;
+        type.getQualifier().writeonly = qualifier.writeonly;
+        type.getQualifier().restrict  = qualifier.restrict;
+    }
     if (qualifier.isAuxiliary() ||
         qualifier.isInterpolation())
         error(loc, "cannot use auxiliary or interpolation qualifiers on a function parameter", "", "");
@@ -2898,6 +2927,14 @@ void TParseContext::setLayoutQualifier(TSourceLoc loc, TPublicType& publicType,
         publicType.qualifier.layoutPacking = ElpStd430;
         return;
     }
+    for (TLayoutFormat format = (TLayoutFormat)(ElfNone + 1); format < ElfCount; format = (TLayoutFormat)(format + 1)) {
+        if (id == TQualifier::getLayoutFormatString(format)) {
+            requireProfile(loc, ENoProfile | ECoreProfile | ECompatibilityProfile, "image load store");
+            profileRequires(loc, ENoProfile | ECoreProfile | ECompatibilityProfile, 420, GL_ARB_shader_image_load_store, "image load store");
+            publicType.qualifier.layoutFormat = format;
+            return;
+        }
+    }
     if (language == EShLangGeometry || language == EShLangTessEvaluation) {
         if (id == TQualifier::getGeometryString(ElgTriangles)) {
             publicType.shaderQualifiers.geometry = ElgTriangles;
@@ -2987,8 +3024,14 @@ void TParseContext::setLayoutQualifier(TSourceLoc loc, TPublicType& publicType,
             publicType.shaderQualifiers.pixelCenterInteger = true;
             return;
         }
+        if (id == "early_fragment_tests") {
+            requireProfile(loc, ENoProfile | ECoreProfile | ECompatibilityProfile, "early_fragment_tests");
+            profileRequires(loc, ENoProfile | ECoreProfile | ECompatibilityProfile, 420, GL_ARB_shader_image_load_store, "early_fragment_tests");
+            publicType.shaderQualifiers.earlyFragmentTests = true;
+            return;
+        }
     }
-    error(loc, "unrecognized layout identifier, or qualifier requires assignemnt (e.g., binding = 4)", id.c_str(), "");
+    error(loc, "unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4)", id.c_str(), "");
 }
 
 // Put the id's layout qualifier value into the public type.  This is before we know any
@@ -3169,6 +3212,9 @@ void TParseContext::mergeObjectLayoutQualifiers(TSourceLoc loc, TQualifier& dst,
     if (src.hasStream())
         dst.layoutStream = src.layoutStream;
 
+    if (src.hasFormat())
+        dst.layoutFormat = src.layoutFormat;
+
     if (src.hasXfbBuffer())
         dst.layoutXfbBuffer = src.layoutXfbBuffer;
 
@@ -3332,6 +3378,23 @@ void TParseContext::layoutTypeCheck(TSourceLoc loc, const TType& type)
         if (type.getBasicType() == EbtBlock)
             error(loc, "only applies to block members, not blocks", "offset", "");        
     }
+
+    // Image format
+    if (qualifier.hasFormat()) {
+        if (type.getBasicType() != EbtSampler || ! type.getSampler().image)
+            error(loc, "only apply to images", TQualifier::getLayoutFormatString(qualifier.layoutFormat), "");
+        else {
+            if (type.getSampler().type == EbtFloat && qualifier.layoutFormat > ElfFloatGuard)
+                error(loc, "does not apply to floating point images", TQualifier::getLayoutFormatString(qualifier.layoutFormat), "");
+            if (type.getSampler().type == EbtInt && (qualifier.layoutFormat < ElfFloatGuard || qualifier.layoutFormat > ElfIntGuard))
+                error(loc, "does not apply to signed integer images", TQualifier::getLayoutFormatString(qualifier.layoutFormat), "");
+            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)
+        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
@@ -4498,6 +4561,12 @@ void TParseContext::updateStandaloneQualifierDefaults(TSourceLoc loc, const TPub
         else
             error(loc, "can only apply to 'in'", "point_mode", "");
     }
+    if (publicType.shaderQualifiers.earlyFragmentTests) {
+        if (publicType.qualifier.storage == EvqVaryingIn)
+            intermediate.setEarlyFragmentTests();
+        else
+            error(loc, "can only apply to 'in'", "early_fragment_tests", "");
+    }
 
     const TQualifier& qualifier = publicType.qualifier;
 
diff --git a/glslang/MachineIndependent/Scan.cpp b/glslang/MachineIndependent/Scan.cpp
index d10369c4e7315edf99f206965ec02061603249bd..a7a72e278210148f3e3d3929550824a21ec34017 100644
--- a/glslang/MachineIndependent/Scan.cpp
+++ b/glslang/MachineIndependent/Scan.cpp
@@ -672,15 +672,17 @@ int TScanContext::tokenizeIdentifier()
             return identifierOrType();
         return keyword;
 
+    case ATOMIC_UINT:
+        return es30ReservedFromGLSL(420);
+
     case COHERENT:
     case RESTRICT:
     case READONLY:
     case WRITEONLY:
-    case ATOMIC_UINT:
-        return es30ReservedFromGLSL(420);
+        return es30ReservedFromGLSL(parseContext.extensionsTurnedOn(1, &GL_ARB_shader_image_load_store) ? 130 : 420);
 
     case VOLATILE:
-        if (parseContext.profile == EEsProfile || parseContext.version < 420)
+        if (! parseContext.symbolTable.atBuiltInLevel() && (parseContext.profile == EEsProfile || (parseContext.version < 420 && ! parseContext.extensionsTurnedOn(1, &GL_ARB_shader_image_load_store))))
             reservedWord();
         return keyword;
 
@@ -766,7 +768,7 @@ int TScanContext::tokenizeIdentifier()
 
     case IMAGECUBEARRAY:
     case IIMAGECUBEARRAY:
-    case UIMAGECUBEARRAY:
+    case UIMAGECUBEARRAY:        
     case IMAGE2DMS:
     case IIMAGE2DMS:
     case UIMAGE2DMS:
@@ -993,6 +995,9 @@ int TScanContext::identifierOrReserved(bool reserved)
 // but then got reserved by ES 3.0.
 int TScanContext::es30ReservedFromGLSL(int version)
 {
+    if (parseContext.symbolTable.atBuiltInLevel())
+        return keyword;
+
     if ((parseContext.profile == EEsProfile && parseContext.version < 300) ||
         (parseContext.profile != EEsProfile && parseContext.version < version)) {
             if (parseContext.forwardCompatible)
@@ -1067,7 +1072,7 @@ int TScanContext::firstGenerationImage()
 {
     afterType = true;
 
-    if (parseContext.profile != EEsProfile && parseContext.version >= 420)
+    if (parseContext.symbolTable.atBuiltInLevel() || (parseContext.profile != EEsProfile && (parseContext.version >= 420 || parseContext.extensionsTurnedOn(1, &GL_ARB_shader_image_load_store))))
         return keyword;
 
     if ((parseContext.profile == EEsProfile && parseContext.version >= 300) ||
@@ -1087,7 +1092,7 @@ int TScanContext::secondGenerationImage()
 {
     afterType = true;
 
-    if (parseContext.profile != EEsProfile && parseContext.version >= 420)
+    if (parseContext.symbolTable.atBuiltInLevel() || parseContext.profile != EEsProfile && (parseContext.version >= 420 || parseContext.extensionsTurnedOn(1, &GL_ARB_shader_image_load_store)))
         return keyword;
 
     if (parseContext.forwardCompatible)
diff --git a/glslang/MachineIndependent/Versions.cpp b/glslang/MachineIndependent/Versions.cpp
index eee23f12ee942172f6d72ef988790d51b666b502..feb233a68c3c6fe508f58d8240e5d8bcaf3068f7 100644
--- a/glslang/MachineIndependent/Versions.cpp
+++ b/glslang/MachineIndependent/Versions.cpp
@@ -166,6 +166,7 @@ void TParseContext::initializeExtensionBehavior()
     extensionBehavior[GL_ARB_texture_cube_map_array]   = EBhDisable;
     extensionBehavior[GL_ARB_shader_texture_lod]       = EBhDisable;
     extensionBehavior[GL_ARB_explicit_attrib_location] = EBhDisablePartial; // "index" for fragment outputs is missing
+    extensionBehavior[GL_ARB_shader_image_load_store]  = EBhDisable;
 }
 
 // Get code that is not part of a shared symbol table, is specific to this shader,
@@ -203,7 +204,8 @@ const char* TParseContext::getPreamble()
             "#define GL_ARB_enhanced_layouts 1\n"
             "#define GL_ARB_texture_cube_map_array 1\n"
             "#define GL_ARB_shader_texture_lod 1\n"
-            "#define GL_ARB_explicit_attrib_location 1\n";
+            "#define GL_ARB_explicit_attrib_location 1\n"
+            "#define GL_ARB_shader_image_load_store 1\n";
     }
 }
 
diff --git a/glslang/MachineIndependent/Versions.h b/glslang/MachineIndependent/Versions.h
index fce980ab3e0a4b9ae4905fea898a39b931cd8be1..0f51ddcded8f2a01fdc0a0bd9295f421479d8a85 100644
--- a/glslang/MachineIndependent/Versions.h
+++ b/glslang/MachineIndependent/Versions.h
@@ -90,6 +90,7 @@ const char* const GL_ARB_enhanced_layouts         = "GL_ARB_enhanced_layouts";
 const char* const GL_ARB_texture_cube_map_array   = "GL_ARB_texture_cube_map_array";
 const char* const GL_ARB_shader_texture_lod       = "GL_ARB_shader_texture_lod";
 const char* const GL_ARB_explicit_attrib_location = "GL_ARB_explicit_attrib_location";
+const char* const GL_ARB_shader_image_load_store  = "GL_ARB_shader_image_load_store";
 
 } // end namespace glslang
 
diff --git a/glslang/MachineIndependent/intermOut.cpp b/glslang/MachineIndependent/intermOut.cpp
index cad4acd27a8afd221d482d8f6bc4878a23e77d09..8cc62f7a2adbd000472ee5c3dad8e197eeb22090 100644
--- a/glslang/MachineIndependent/intermOut.cpp
+++ b/glslang/MachineIndependent/intermOut.cpp
@@ -611,6 +611,8 @@ void TIntermediate::output(TInfoSink& infoSink, bool tree)
             infoSink.debug << "gl_FragCoord pixel center is integer\n";
         if (originUpperLeft)
             infoSink.debug << "gl_FragCoord origin is upper left\n";
+        if (earlyFragmentTests)
+            infoSink.debug << "using early_fragment_tests\n";
         break;
 
     case EShLangCompute:
diff --git a/glslang/MachineIndependent/linkValidate.cpp b/glslang/MachineIndependent/linkValidate.cpp
index 6625a34ef944b3607bed79b7b245868ba92ba176..b53bc31b47dc7f5266cb0e05ae65fdeaf6a5d43d 100644
--- a/glslang/MachineIndependent/linkValidate.cpp
+++ b/glslang/MachineIndependent/linkValidate.cpp
@@ -80,6 +80,9 @@ void TIntermediate::merge(TInfoSink& infoSink, TIntermediate& unit)
     if (originUpperLeft != unit.originUpperLeft || pixelCenterInteger != unit.pixelCenterInteger)
         error(infoSink, "gl_FragCoord redeclarations must match across shaders\n");
 
+    if (! earlyFragmentTests)
+        earlyFragmentTests = unit.earlyFragmentTests;
+
     if (inputPrimitive == ElgNone)
         inputPrimitive = unit.inputPrimitive;
     else if (inputPrimitive != unit.inputPrimitive)
diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h
index 1e7e5d6c631165b3f3df0b65bdc657fec79b05b2..00d7ba222ec0c45bd01386c00afedfea38c436de 100644
--- a/glslang/MachineIndependent/localintermediate.h
+++ b/glslang/MachineIndependent/localintermediate.h
@@ -112,7 +112,7 @@ public:
     explicit TIntermediate(EShLanguage l, int v = 0, EProfile p = ENoProfile) : language(l), treeRoot(0), profile(p), version(v), 
         numMains(0), numErrors(0), recursive(false),
         invocations(0), vertices(0), inputPrimitive(ElgNone), outputPrimitive(ElgNone), pixelCenterInteger(false), originUpperLeft(false),
-        vertexSpacing(EvsNone), vertexOrder(EvoNone), pointMode(false), xfbMode(false)
+        vertexSpacing(EvsNone), vertexOrder(EvoNone), pointMode(false), earlyFragmentTests(false), xfbMode(false)
     {
         xfbBuffers.resize(TQualifier::layoutXfbBufferEnd);
     }
@@ -235,6 +235,8 @@ public:
     bool getOriginUpperLeft() const { return originUpperLeft; }
     void setPixelCenterInteger() { pixelCenterInteger = true; }
     bool getPixelCenterInteger() const { return pixelCenterInteger; }
+    void setEarlyFragmentTests() { earlyFragmentTests = true; }
+    bool getEarlyFragmentTests() const { return earlyFragmentTests; }
 
     void addToCallGraph(TInfoSink&, const TString& caller, const TString& callee);
     void merge(TInfoSink&, TIntermediate&);
@@ -287,6 +289,7 @@ protected:
     TVertexSpacing vertexSpacing;
     TVertexOrder vertexOrder;
     bool pointMode;
+    bool earlyFragmentTests;
     bool xfbMode;
 
     typedef std::list<TCall> TGraph;