Implement GL_EXT_scalar_block_layout
diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp
index c58013b..a93a4ed 100755
--- a/SPIRV/GlslangToSpv.cpp
+++ b/SPIRV/GlslangToSpv.cpp
@@ -3459,6 +3459,7 @@
     switch (type.getQualifier().layoutPacking) {
     case glslang::ElpStd140:
     case glslang::ElpStd430:
+    case glslang::ElpScalar:
         return type.getQualifier().layoutPacking;
     default:
         return glslang::ElpNone;
@@ -3470,7 +3471,7 @@
 {
     int size;
     int stride;
-    glslangIntermediate->getBaseAlignment(arrayType, size, stride, explicitLayout == glslang::ElpStd140, matrixLayout == glslang::ElmRowMajor);
+    glslangIntermediate->getMemberAlignment(arrayType, size, stride, explicitLayout, matrixLayout == glslang::ElmRowMajor);
 
     return stride;
 }
@@ -3485,7 +3486,7 @@
 
     int size;
     int stride;
-    glslangIntermediate->getBaseAlignment(elementType, size, stride, explicitLayout == glslang::ElpStd140, matrixLayout == glslang::ElmRowMajor);
+    glslangIntermediate->getMemberAlignment(elementType, size, stride, explicitLayout, matrixLayout == glslang::ElmRowMajor);
 
     return stride;
 }
@@ -3527,7 +3528,7 @@
 
     int memberSize;
     int dummyStride;
-    int memberAlignment = glslangIntermediate->getBaseAlignment(memberType, memberSize, dummyStride, explicitLayout == glslang::ElpStd140, matrixLayout == glslang::ElmRowMajor);
+    int memberAlignment = glslangIntermediate->getMemberAlignment(memberType, memberSize, dummyStride, explicitLayout, matrixLayout == glslang::ElmRowMajor);
 
     // Adjust alignment for HLSL rules
     // TODO: make this consistent in early phases of code:
@@ -3546,7 +3547,7 @@
     glslang::RoundToPow2(currentOffset, memberAlignment);
 
     // Bump up to vec4 if there is a bad straddle
-    if (glslangIntermediate->improperStraddle(memberType, memberSize, currentOffset))
+    if (explicitLayout != glslang::ElpScalar && glslangIntermediate->improperStraddle(memberType, memberSize, currentOffset))
         glslang::RoundToPow2(currentOffset, 16);
 
     nextOffset = currentOffset + memberSize;
diff --git a/Test/baseResults/300.vert.out b/Test/baseResults/300.vert.out
index 95ebb92..d8c9e16 100644
--- a/Test/baseResults/300.vert.out
+++ b/Test/baseResults/300.vert.out
@@ -39,7 +39,7 @@
 ERROR: 0:169: 'Bblock' : cannot add storage, auxiliary, memory, interpolation, layout, or precision qualifier to an existing variable 
 ERROR: 0:170: 'Bfoo' : cannot add storage, auxiliary, memory, interpolation, layout, or precision qualifier to an existing variable 
 ERROR: 0:172: 'std430' : not supported for this version or the enabled extensions 
-ERROR: 0:172: 'std430' : requires the 'buffer' storage qualifier 
+ERROR: 0:172: 'std430 requires the buffer storage qualifier' : required extension not requested: GL_EXT_scalar_block_layout
 ERROR: 0:175: '' : array size required 
 ERROR: 0:185: 'assign' :  cannot convert from ' temp 4-element array of highp float' to ' temp 3-element array of highp float'
 ERROR: 0:186: 'assign' :  cannot convert from ' temp 3-element array of highp float' to ' temp 4-element array of highp float'
diff --git a/Test/baseResults/310.vert.out b/Test/baseResults/310.vert.out
index 21fa27b..baf0987 100644
--- a/Test/baseResults/310.vert.out
+++ b/Test/baseResults/310.vert.out
@@ -15,7 +15,7 @@
 ERROR: 0:79: 'vertex-shader array-of-struct output' : not supported with this profile: es
 ERROR: 0:81: 'vertex-shader struct output containing an array' : not supported with this profile: es
 ERROR: 0:83: 'vertex-shader struct output containing structure' : not supported with this profile: es
-ERROR: 0:85: 'std430' : requires the 'buffer' storage qualifier 
+ERROR: 0:85: 'std430 requires the buffer storage qualifier' : required extension not requested: GL_EXT_scalar_block_layout
 ERROR: 0:97: 's' : member of block cannot be or contain a sampler, image, or atomic_uint type 
 ERROR: 0:105: 'location' : overlapping use of location 12
 ERROR: 0:107: 'input block' : not supported in this stage: vertex
diff --git a/Test/baseResults/420.vert.out b/Test/baseResults/420.vert.out
index 25bce16..22577ab 100644
--- a/Test/baseResults/420.vert.out
+++ b/Test/baseResults/420.vert.out
@@ -46,7 +46,7 @@
 ERROR: 0:143: 'rgba32ui' : does not apply to signed integer images 
 ERROR: 0:144: 'r8ui' : does not apply to signed integer images 
 ERROR: 0:147: 'offset on block member' : not supported for this version or the enabled extensions 
-ERROR: 0:147: 'offset/align' : can only be used with std140 or std430 layout packing 
+ERROR: 0:147: 'offset/align' : can only be used with std140, std430, or scalar layout packing 
 ERROR: 0:157: 'textureQueryLevels' : no matching overloaded function found 
 ERROR: 0:157: 'assign' :  cannot convert from ' const float' to ' temp int'
 ERROR: 0:158: 'textureQueryLevels' : no matching overloaded function found 
diff --git a/Test/baseResults/430.vert.out b/Test/baseResults/430.vert.out
index 29ffb01..f57a39c 100644
--- a/Test/baseResults/430.vert.out
+++ b/Test/baseResults/430.vert.out
@@ -27,9 +27,9 @@
 ERROR: 0:65: 'uniform buffer-member align' : not supported for this version or the enabled extensions 
 ERROR: 0:65: 'offset on block member' : not supported for this version or the enabled extensions 
 ERROR: 0:66: 'offset on block member' : not supported for this version or the enabled extensions 
-ERROR: 0:64: 'align' : can only be used with std140 or std430 layout packing 
-ERROR: 0:65: 'offset/align' : can only be used with std140 or std430 layout packing 
-ERROR: 0:66: 'offset/align' : can only be used with std140 or std430 layout packing 
+ERROR: 0:64: 'align' : can only be used with std140, std430, or scalar layout packing 
+ERROR: 0:65: 'offset/align' : can only be used with std140, std430, or scalar layout packing 
+ERROR: 0:66: 'offset/align' : can only be used with std140, std430, or scalar layout packing 
 ERROR: 0:71: 'offset on block member' : not supported for this version or the enabled extensions 
 ERROR: 0:74: 'gl_MaxTransformFeedbackBuffers' : required extension not requested: GL_ARB_enhanced_layouts
 ERROR: 0:75: 'gl_MaxTransformFeedbackInterleavedComponents' : required extension not requested: GL_ARB_enhanced_layouts
diff --git a/Test/baseResults/440.frag.out b/Test/baseResults/440.frag.out
index 18e014f..1ac6e7c 100644
--- a/Test/baseResults/440.frag.out
+++ b/Test/baseResults/440.frag.out
@@ -21,11 +21,11 @@
 ERROR: 0:39: 'output block' : not supported in this stage: fragment
 ERROR: 0:39: 'layout' : offset/align can only be used on a uniform or buffer 
 ERROR: 0:39: 'offset' : only applies to block members, not blocks 
-ERROR: 0:42: 'align' : can only be used with std140 or std430 layout packing 
-ERROR: 0:43: 'align' : can only be used with std140 or std430 layout packing 
+ERROR: 0:42: 'align' : can only be used with std140, std430, or scalar layout packing 
+ERROR: 0:43: 'align' : can only be used with std140, std430, or scalar layout packing 
 ERROR: 0:43: 'layout' : offset/align can only be used on a uniform or buffer 
 ERROR: 0:44: 'output block' : not supported in this stage: fragment
-ERROR: 0:44: 'align' : can only be used with std140 or std430 layout packing 
+ERROR: 0:44: 'align' : can only be used with std140, std430, or scalar layout packing 
 ERROR: 0:44: 'layout' : offset/align can only be used on a uniform or buffer 
 ERROR: 0:46: 'offset' : cannot specify on a variable declaration 
 ERROR: 0:47: 'layout' : offset/align can only be used on a uniform or buffer 
@@ -36,9 +36,9 @@
 ERROR: 0:54: 'layout' : matrix or packing qualifiers can only be used on a uniform or buffer 
 ERROR: 0:55: 'layout' : cannot specify packing on a variable declaration 
 ERROR: 0:57: 'align' : must be a power of 2 
-ERROR: 0:58: 'offset/align' : can only be used with std140 or std430 layout packing 
-ERROR: 0:62: 'offset/align' : can only be used with std140 or std430 layout packing 
-ERROR: 0:63: 'offset/align' : can only be used with std140 or std430 layout packing 
+ERROR: 0:58: 'offset/align' : can only be used with std140, std430, or scalar layout packing 
+ERROR: 0:62: 'offset/align' : can only be used with std140, std430, or scalar layout packing 
+ERROR: 0:63: 'offset/align' : can only be used with std140, std430, or scalar layout packing 
 ERROR: 0:62: 'layout' : offset/align can only be used on a uniform or buffer 
 ERROR: 0:63: 'layout' : offset/align can only be used on a uniform or buffer 
 ERROR: 0:84: 'align' : must be a power of 2 
diff --git a/Test/baseResults/spv.scalarlayout.frag.out b/Test/baseResults/spv.scalarlayout.frag.out
new file mode 100644
index 0000000..2935e1a
--- /dev/null
+++ b/Test/baseResults/spv.scalarlayout.frag.out
@@ -0,0 +1,80 @@
+spv.scalarlayout.frag
+error: SPIRV-Tools Validation Errors
+error: Structure id 17 decorated as Block for variable in Uniform storage class must follow standard uniform buffer layout rules: member 1 at offset 4 is not aligned to 8
+  %B1 = OpTypeStruct %float %v2float %v3float %_arr_float_uint_2 %mat2v3float %_arr_mat2v3float_uint_2 %float %S %_arr_S_uint_2
+
+// Module Version 10000
+// Generated by (magic number): 80007
+// Id's are bound by 20
+
+                              Capability Shader
+                              Capability Float64
+               1:             ExtInstImport  "GLSL.std.450"
+                              MemoryModel Logical GLSL450
+                              EntryPoint Fragment 4  "main"
+                              ExecutionMode 4 OriginUpperLeft
+                              Source GLSL 450
+                              SourceExtension  "GL_EXT_scalar_block_layout"
+                              Name 4  "main"
+                              Name 15  "S"
+                              MemberName 15(S) 0  "a"
+                              MemberName 15(S) 1  "b"
+                              MemberName 15(S) 2  "c"
+                              MemberName 15(S) 3  "d"
+                              MemberName 15(S) 4  "e"
+                              MemberName 15(S) 5  "f"
+                              Name 17  "B1"
+                              MemberName 17(B1) 0  "a"
+                              MemberName 17(B1) 1  "b"
+                              MemberName 17(B1) 2  "c"
+                              MemberName 17(B1) 3  "d"
+                              MemberName 17(B1) 4  "e"
+                              MemberName 17(B1) 5  "f"
+                              MemberName 17(B1) 6  "g"
+                              MemberName 17(B1) 7  "h"
+                              MemberName 17(B1) 8  "i"
+                              Name 19  ""
+                              Decorate 11 ArrayStride 4
+                              Decorate 13 ArrayStride 24
+                              MemberDecorate 15(S) 0 Offset 0
+                              MemberDecorate 15(S) 1 Offset 4
+                              MemberDecorate 15(S) 2 Offset 16
+                              MemberDecorate 15(S) 3 Offset 24
+                              MemberDecorate 15(S) 4 Offset 28
+                              MemberDecorate 15(S) 5 Offset 40
+                              Decorate 16 ArrayStride 48
+                              MemberDecorate 17(B1) 0 Offset 0
+                              MemberDecorate 17(B1) 1 Offset 4
+                              MemberDecorate 17(B1) 2 Offset 12
+                              MemberDecorate 17(B1) 3 Offset 24
+                              MemberDecorate 17(B1) 4 ColMajor
+                              MemberDecorate 17(B1) 4 Offset 32
+                              MemberDecorate 17(B1) 4 MatrixStride 12
+                              MemberDecorate 17(B1) 5 ColMajor
+                              MemberDecorate 17(B1) 5 Offset 56
+                              MemberDecorate 17(B1) 5 MatrixStride 12
+                              MemberDecorate 17(B1) 6 Offset 104
+                              MemberDecorate 17(B1) 7 Offset 112
+                              MemberDecorate 17(B1) 8 Offset 160
+                              Decorate 17(B1) Block
+                              Decorate 19 DescriptorSet 0
+               2:             TypeVoid
+               3:             TypeFunction 2
+               6:             TypeFloat 32
+               7:             TypeVector 6(float) 2
+               8:             TypeVector 6(float) 3
+               9:             TypeInt 32 0
+              10:      9(int) Constant 2
+              11:             TypeArray 6(float) 10
+              12:             TypeMatrix 8(fvec3) 2
+              13:             TypeArray 12 10
+              14:             TypeFloat 64
+           15(S):             TypeStruct 6(float) 7(fvec2) 14(float64_t) 6(float) 8(fvec3) 6(float)
+              16:             TypeArray 15(S) 10
+          17(B1):             TypeStruct 6(float) 7(fvec2) 8(fvec3) 11 12 13 6(float) 15(S) 16
+              18:             TypePointer Uniform 17(B1)
+              19:     18(ptr) Variable Uniform
+         4(main):           2 Function None 3
+               5:             Label
+                              Return
+                              FunctionEnd
diff --git a/Test/baseResults/spv.scalarlayoutfloat16.frag.out b/Test/baseResults/spv.scalarlayoutfloat16.frag.out
new file mode 100644
index 0000000..9118636
--- /dev/null
+++ b/Test/baseResults/spv.scalarlayoutfloat16.frag.out
@@ -0,0 +1,72 @@
+spv.scalarlayoutfloat16.frag
+error: SPIRV-Tools Validation Errors
+error: Structure id 15 decorated as Block for variable in Uniform storage class must follow standard uniform buffer layout rules: member 1 at offset 2 is not aligned to 4
+  %B1 = OpTypeStruct %half %v2half %v3half %_arr_half_uint_2 %half %S %_arr_S_uint_2
+
+// Module Version 10000
+// Generated by (magic number): 80007
+// Id's are bound by 18
+
+                              Capability Shader
+                              Capability Float64
+                              Capability StorageUniform16
+                              Extension  "SPV_KHR_16bit_storage"
+               1:             ExtInstImport  "GLSL.std.450"
+                              MemoryModel Logical GLSL450
+                              EntryPoint Fragment 4  "main"
+                              ExecutionMode 4 OriginUpperLeft
+                              Source GLSL 450
+                              SourceExtension  "GL_EXT_scalar_block_layout"
+                              SourceExtension  "GL_EXT_shader_16bit_storage"
+                              Name 4  "main"
+                              Name 13  "S"
+                              MemberName 13(S) 0  "a"
+                              MemberName 13(S) 1  "b"
+                              MemberName 13(S) 2  "c"
+                              MemberName 13(S) 3  "d"
+                              MemberName 13(S) 4  "e"
+                              MemberName 13(S) 5  "f"
+                              Name 15  "B1"
+                              MemberName 15(B1) 0  "a"
+                              MemberName 15(B1) 1  "b"
+                              MemberName 15(B1) 2  "c"
+                              MemberName 15(B1) 3  "d"
+                              MemberName 15(B1) 4  "g"
+                              MemberName 15(B1) 5  "h"
+                              MemberName 15(B1) 6  "i"
+                              Name 17  ""
+                              Decorate 11 ArrayStride 2
+                              MemberDecorate 13(S) 0 Offset 0
+                              MemberDecorate 13(S) 1 Offset 2
+                              MemberDecorate 13(S) 2 Offset 8
+                              MemberDecorate 13(S) 3 Offset 16
+                              MemberDecorate 13(S) 4 Offset 18
+                              MemberDecorate 13(S) 5 Offset 24
+                              Decorate 14 ArrayStride 32
+                              MemberDecorate 15(B1) 0 Offset 0
+                              MemberDecorate 15(B1) 1 Offset 2
+                              MemberDecorate 15(B1) 2 Offset 6
+                              MemberDecorate 15(B1) 3 Offset 12
+                              MemberDecorate 15(B1) 4 Offset 16
+                              MemberDecorate 15(B1) 5 Offset 24
+                              MemberDecorate 15(B1) 6 Offset 56
+                              Decorate 15(B1) Block
+                              Decorate 17 DescriptorSet 0
+               2:             TypeVoid
+               3:             TypeFunction 2
+               6:             TypeFloat 16
+               7:             TypeVector 6(float16_t) 2
+               8:             TypeVector 6(float16_t) 3
+               9:             TypeInt 32 0
+              10:      9(int) Constant 2
+              11:             TypeArray 6(float16_t) 10
+              12:             TypeFloat 64
+           13(S):             TypeStruct 6(float16_t) 7(f16vec2) 12(float64_t) 6(float16_t) 8(f16vec3) 6(float16_t)
+              14:             TypeArray 13(S) 10
+          15(B1):             TypeStruct 6(float16_t) 7(f16vec2) 8(f16vec3) 11 6(float16_t) 13(S) 14
+              16:             TypePointer Uniform 15(B1)
+              17:     16(ptr) Variable Uniform
+         4(main):           2 Function None 3
+               5:             Label
+                              Return
+                              FunctionEnd
diff --git a/Test/spv.scalarlayout.frag b/Test/spv.scalarlayout.frag
new file mode 100644
index 0000000..c7ecf50
--- /dev/null
+++ b/Test/spv.scalarlayout.frag
@@ -0,0 +1,32 @@
+#version 450 core

+

+#extension GL_EXT_scalar_block_layout : enable

+

+// Block memory layout

+struct S

+{

+    float      a;   // offset 0

+    vec2       b;   // offset 4

+    double     c;   // offset 16

+    float      d;   // offset 24

+    vec3       e;   // offset 28

+    float      f;   // offset 40

+    // size = 44, align = 8

+};

+

+layout(column_major, scalar) uniform B1

+{

+    float      a;     // offset = 0

+    vec2       b;     // offset = 4

+    vec3       c;     // offset = 12

+    float      d[2];  // offset = 24

+    mat2x3     e;     // offset = 32, takes 24 bytes, matrixstride = 12

+    mat2x3     f[2];  // offset = 56, takes 48 bytes, matrixstride = 12, arraystride = 24

+    float      g;     // offset = 104

+    S          h;     // offset = 112 (aligned to multiple of 8)

+    S          i[2];  // offset = 160 (aligned to multiple of 8) stride = 48

+};

+

+void main()

+{

+}

diff --git a/Test/spv.scalarlayoutfloat16.frag b/Test/spv.scalarlayoutfloat16.frag
new file mode 100644
index 0000000..ff87097
--- /dev/null
+++ b/Test/spv.scalarlayoutfloat16.frag
@@ -0,0 +1,31 @@
+#version 450 core

+

+#extension GL_EXT_shader_16bit_storage: enable

+#extension GL_EXT_scalar_block_layout : enable

+

+// Block memory layout

+struct S

+{

+    float16_t      a;   // offset 0

+    f16vec2        b;   // offset 2

+    double         c;   // offset 8

+    float16_t      d;   // offset 16

+    f16vec3        e;   // offset 18

+    float16_t      f;   // offset 24

+    // size = 26, align = 8

+};

+

+layout(column_major, scalar) uniform B1

+{

+    float16_t      a;     // offset = 0

+    f16vec2        b;     // offset = 2

+    f16vec3        c;     // offset = 6

+    float16_t      d[2];  // offset = 12 stride = 2

+    float16_t      g;     // offset = 16

+    S              h;     // offset = 24 (aligned to multiple of 8)

+    S              i[2];  // offset = 56 (aligned to multiple of 8) stride = 32

+};

+

+void main()

+{

+}

diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h
index ae9cf40..b8b2c6f 100644
--- a/glslang/Include/Types.h
+++ b/glslang/Include/Types.h
@@ -277,6 +277,7 @@
     ElpStd140,
     ElpStd430,
     ElpPacked,
+    ElpScalar,
     ElpCount        // If expanding, see bitfield width below
 };
 
@@ -951,6 +952,7 @@
         case ElpShared:   return "shared";
         case ElpStd140:   return "std140";
         case ElpStd430:   return "std430";
+        case ElpScalar:   return "scalar";
         default:          return "none";
         }
     }
diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp
index 56b45ca..24bd417 100755
--- a/glslang/MachineIndependent/ParseHelper.cpp
+++ b/glslang/MachineIndependent/ParseHelper.cpp
@@ -4611,6 +4611,12 @@
         publicType.qualifier.layoutPacking = ElpStd430;
         return;
     }
+    if (id == TQualifier::getLayoutPackingString(ElpScalar)) {
+        requireVulkan(loc, "scalar");
+        requireExtensions(loc, 1, &E_GL_EXT_scalar_block_layout, "scalar block layout");
+        publicType.qualifier.layoutPacking = ElpScalar;
+        return;
+    }
     // TODO: compile-time performance: may need to stop doing linear searches
     for (TLayoutFormat format = (TLayoutFormat)(ElfNone + 1); format < ElfCount; format = (TLayoutFormat)(format + 1)) {
         if (id == TQualifier::getLayoutFormatString(format)) {
@@ -6784,8 +6790,10 @@
 
     // "The align qualifier can only be used on blocks or block members, and only for blocks declared with std140 or std430 layouts."
     if (currentBlockQualifier.hasAlign()) {
-        if (defaultQualification.layoutPacking != ElpStd140 && defaultQualification.layoutPacking != ElpStd430) {
-            error(loc, "can only be used with std140 or std430 layout packing", "align", "");
+        if (defaultQualification.layoutPacking != ElpStd140 &&
+            defaultQualification.layoutPacking != ElpStd430 &&
+            defaultQualification.layoutPacking != ElpScalar) {
+            error(loc, "can only be used with std140, std430, or scalar layout packing", "align", "");
             defaultQualification.layoutAlign = -1;
         }
     }
@@ -6834,8 +6842,10 @@
         // "The offset qualifier can only be used on block members of blocks declared with std140 or std430 layouts."
         // "The align qualifier can only be used on blocks or block members, and only for blocks declared with std140 or std430 layouts."
         if (memberQualifier.hasAlign() || memberQualifier.hasOffset()) {
-            if (defaultQualification.layoutPacking != ElpStd140 && defaultQualification.layoutPacking != ElpStd430)
-                error(memberLoc, "can only be used with std140 or std430 layout packing", "offset/align", "");
+            if (defaultQualification.layoutPacking != ElpStd140 &&
+                defaultQualification.layoutPacking != ElpStd430 &&
+                defaultQualification.layoutPacking != ElpScalar)
+                error(memberLoc, "can only be used with std140, std430, or scalar layout packing", "offset/align", "");
         }
 
 #ifdef NV_EXTENSIONS
@@ -6946,7 +6956,7 @@
         profileRequires(loc, EEsProfile, 300, nullptr, "uniform block");
         profileRequires(loc, ENoProfile, 140, nullptr, "uniform block");
         if (currentBlockQualifier.layoutPacking == ElpStd430 && ! currentBlockQualifier.layoutPushConstant)
-            error(loc, "requires the 'buffer' storage qualifier", "std430", "");
+            requireExtensions(loc, 1, &E_GL_EXT_scalar_block_layout, "std430 requires the buffer storage qualifier");
         break;
     case EvqBuffer:
         requireProfile(loc, EEsProfile | ECoreProfile | ECompatibilityProfile, "buffer block");
@@ -7145,7 +7155,7 @@
 {
     if (!qualifier.isUniformOrBuffer() && !qualifier.isTaskMemory())
         return;
-    if (qualifier.layoutPacking != ElpStd140 && qualifier.layoutPacking != ElpStd430)
+    if (qualifier.layoutPacking != ElpStd140 && qualifier.layoutPacking != ElpStd430 && qualifier.layoutPacking != ElpScalar)
         return;
 
     int offset = 0;
@@ -7159,8 +7169,8 @@
         // modify just the children's view of matrix layout, if there is one for this member
         TLayoutMatrix subMatrixLayout = typeList[member].type->getQualifier().layoutMatrix;
         int dummyStride;
-        int memberAlignment = intermediate.getBaseAlignment(*typeList[member].type, memberSize, dummyStride, qualifier.layoutPacking == ElpStd140,
-                                                            subMatrixLayout != ElmNone ? subMatrixLayout == ElmRowMajor : qualifier.layoutMatrix == ElmRowMajor);
+        int memberAlignment = intermediate.getMemberAlignment(*typeList[member].type, memberSize, dummyStride, qualifier.layoutPacking,
+                                                              subMatrixLayout != ElmNone ? subMatrixLayout == ElmRowMajor : qualifier.layoutMatrix == ElmRowMajor);
         if (memberQualifier.hasOffset()) {
             // "The specified offset must be a multiple
             // of the base alignment of the type of the block member it qualifies, or a compile-time error results."
diff --git a/glslang/MachineIndependent/Versions.cpp b/glslang/MachineIndependent/Versions.cpp
index 66fa3e2..89c0333 100644
--- a/glslang/MachineIndependent/Versions.cpp
+++ b/glslang/MachineIndependent/Versions.cpp
@@ -204,6 +204,7 @@
     extensionBehavior[E_GL_EXT_control_flow_attributes]                 = EBhDisable;
     extensionBehavior[E_GL_EXT_nonuniform_qualifier]                    = EBhDisable;
     extensionBehavior[E_GL_EXT_samplerless_texture_functions]           = EBhDisable;
+    extensionBehavior[E_GL_EXT_scalar_block_layout]                     = EBhDisable;
 
     extensionBehavior[E_GL_EXT_shader_16bit_storage]                    = EBhDisable;
     extensionBehavior[E_GL_EXT_shader_8bit_storage]                     = EBhDisable;
@@ -378,6 +379,7 @@
             "#define GL_EXT_shader_16bit_storage 1\n"
             "#define GL_EXT_shader_8bit_storage 1\n"
             "#define GL_EXT_samplerless_texture_functions 1\n"
+            "#define GL_EXT_scalar_block_layout 1\n"
 
             // GL_KHR_shader_subgroup
             "#define GL_KHR_shader_subgroup_basic 1\n"
diff --git a/glslang/MachineIndependent/Versions.h b/glslang/MachineIndependent/Versions.h
index 85c93c0..df10f0f 100644
--- a/glslang/MachineIndependent/Versions.h
+++ b/glslang/MachineIndependent/Versions.h
@@ -166,6 +166,7 @@
 const char* const E_GL_EXT_control_flow_attributes          = "GL_EXT_control_flow_attributes";
 const char* const E_GL_EXT_nonuniform_qualifier             = "GL_EXT_nonuniform_qualifier";
 const char* const E_GL_EXT_samplerless_texture_functions    = "GL_EXT_samplerless_texture_functions";
+const char* const E_GL_EXT_scalar_block_layout              = "GL_EXT_scalar_block_layout";
 
 // Arrays of extensions for the above viewportEXTs duplications
 
diff --git a/glslang/MachineIndependent/linkValidate.cpp b/glslang/MachineIndependent/linkValidate.cpp
index 8630128..82e7c6e 100644
--- a/glslang/MachineIndependent/linkValidate.cpp
+++ b/glslang/MachineIndependent/linkValidate.cpp
@@ -1372,10 +1372,11 @@
 // stride comes from the flattening down to vectors.
 //
 // Return value is the alignment of the type.
-int TIntermediate::getBaseAlignment(const TType& type, int& size, int& stride, bool std140, bool rowMajor)
+int TIntermediate::getBaseAlignment(const TType& type, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor)
 {
     int alignment;
 
+    bool std140 = layoutPacking == glslang::ElpStd140;
     // When using the std140 storage layout, structures will be laid out in buffer
     // storage with its members stored in monotonically increasing order based on their
     // location in the declaration. A structure and each structure member have a base
@@ -1439,7 +1440,7 @@
     if (type.isArray()) {
         // TODO: perf: this might be flattened by using getCumulativeArraySize(), and a deref that discards all arrayness
         TType derefType(type, 0);
-        alignment = getBaseAlignment(derefType, size, dummyStride, std140, rowMajor);
+        alignment = getBaseAlignment(derefType, size, dummyStride, layoutPacking, rowMajor);
         if (std140)
             alignment = std::max(baseAlignmentVec4Std140, alignment);
         RoundToPow2(size, alignment);
@@ -1459,7 +1460,7 @@
             int memberSize;
             // modify just the children's view of matrix layout, if there is one for this member
             TLayoutMatrix subMatrixLayout = memberList[m].type->getQualifier().layoutMatrix;
-            int memberAlignment = getBaseAlignment(*memberList[m].type, memberSize, dummyStride, std140,
+            int memberAlignment = getBaseAlignment(*memberList[m].type, memberSize, dummyStride, layoutPacking,
                                                    (subMatrixLayout != ElmNone) ? (subMatrixLayout == ElmRowMajor) : rowMajor);
             maxAlignment = std::max(maxAlignment, memberAlignment);
             RoundToPow2(size, memberAlignment);
@@ -1498,7 +1499,7 @@
         // rule 5: deref to row, not to column, meaning the size of vector is num columns instead of num rows
         TType derefType(type, 0, rowMajor);
 
-        alignment = getBaseAlignment(derefType, size, dummyStride, std140, rowMajor);
+        alignment = getBaseAlignment(derefType, size, dummyStride, layoutPacking, rowMajor);
         if (std140)
             alignment = std::max(baseAlignmentVec4Std140, alignment);
         RoundToPow2(size, alignment);
@@ -1526,4 +1527,79 @@
                       : offset % 16 != 0;
 }
 
+int TIntermediate::getScalarAlignment(const TType& type, int& size, int& stride, bool rowMajor)
+{
+    int alignment;
+
+    stride = 0;
+    int dummyStride;
+
+    if (type.isArray()) {
+        TType derefType(type, 0);
+        alignment = getScalarAlignment(derefType, size, dummyStride, rowMajor);
+
+        stride = size;
+        RoundToPow2(stride, alignment);
+
+        size = stride * (type.getOuterArraySize() - 1) + size;
+        return alignment;
+    }
+
+    if (type.getBasicType() == EbtStruct) {
+        const TTypeList& memberList = *type.getStruct();
+
+        size = 0;
+        int maxAlignment = 0;
+        for (size_t m = 0; m < memberList.size(); ++m) {
+            int memberSize;
+            // modify just the children's view of matrix layout, if there is one for this member
+            TLayoutMatrix subMatrixLayout = memberList[m].type->getQualifier().layoutMatrix;
+            int memberAlignment = getScalarAlignment(*memberList[m].type, memberSize, dummyStride,
+                                                     (subMatrixLayout != ElmNone) ? (subMatrixLayout == ElmRowMajor) : rowMajor);
+            maxAlignment = std::max(maxAlignment, memberAlignment);
+            RoundToPow2(size, memberAlignment);
+            size += memberSize;
+        }
+
+        return maxAlignment;
+    }
+
+    if (type.isScalar())
+        return getBaseAlignmentScalar(type, size);
+
+    if (type.isVector()) {
+        int scalarAlign = getBaseAlignmentScalar(type, size);
+        
+        size *= type.getVectorSize();
+        return scalarAlign;
+    }
+
+    if (type.isMatrix()) {
+        TType derefType(type, 0, rowMajor);
+
+        alignment = getScalarAlignment(derefType, size, dummyStride, rowMajor);
+
+        stride = size;  // use intra-matrix stride for stride of a just a matrix
+        if (rowMajor)
+            size = stride * type.getMatrixRows();
+        else
+            size = stride * type.getMatrixCols();
+
+        return alignment;
+    }
+
+    assert(0);  // all cases should be covered above
+    size = 1;
+    return 1;    
+}
+
+int TIntermediate::getMemberAlignment(const TType& type, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor)
+{
+    if (layoutPacking == glslang::ElpScalar) {
+        return getScalarAlignment(type, size, stride, rowMajor);
+    } else {
+        return getBaseAlignment(type, size, stride, layoutPacking, rowMajor);
+    }
+}
+
 } // end namespace glslang
diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h
index 99f777f..762b310 100755
--- a/glslang/MachineIndependent/localintermediate.h
+++ b/glslang/MachineIndependent/localintermediate.h
@@ -634,7 +634,9 @@
     int addXfbBufferOffset(const TType&);
     unsigned int computeTypeXfbSize(const TType&, bool& containsDouble) const;
     static int getBaseAlignmentScalar(const TType&, int& size);
-    static int getBaseAlignment(const TType&, int& size, int& stride, bool std140, bool rowMajor);
+    static int getBaseAlignment(const TType&, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor);
+    static int getScalarAlignment(const TType&, int& size, int& stride, bool rowMajor);
+    static int getMemberAlignment(const TType&, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor);
     static bool improperStraddle(const TType& type, int size, int offset);
     bool promote(TIntermOperator*);
 
diff --git a/glslang/MachineIndependent/reflection.cpp b/glslang/MachineIndependent/reflection.cpp
index 5d59f28..8cfc2ac 100644
--- a/glslang/MachineIndependent/reflection.cpp
+++ b/glslang/MachineIndependent/reflection.cpp
@@ -131,11 +131,11 @@
         for (int m = 0; m <= index; ++m) {
             // modify just the children's view of matrix layout, if there is one for this member
             TLayoutMatrix subMatrixLayout = memberList[m].type->getQualifier().layoutMatrix;
-            int memberAlignment = intermediate.getBaseAlignment(*memberList[m].type, memberSize, dummyStride,
-                                                                type.getQualifier().layoutPacking == ElpStd140,
-                                                                subMatrixLayout != ElmNone
-                                                                    ? subMatrixLayout == ElmRowMajor
-                                                                    : type.getQualifier().layoutMatrix == ElmRowMajor);
+            int memberAlignment = intermediate.getMemberAlignment(*memberList[m].type, memberSize, dummyStride,
+                                                                  type.getQualifier().layoutPacking,
+                                                                  subMatrixLayout != ElmNone
+                                                                      ? subMatrixLayout == ElmRowMajor
+                                                                      : type.getQualifier().layoutMatrix == ElmRowMajor);
             RoundToPow2(offset, memberAlignment);
             if (m < index)
                 offset += memberSize;
@@ -154,9 +154,9 @@
 
         int lastMemberSize;
         int dummyStride;
-        intermediate.getBaseAlignment(*memberList[lastIndex].type, lastMemberSize, dummyStride,
-                                      blockType.getQualifier().layoutPacking == ElpStd140,
-                                      blockType.getQualifier().layoutMatrix == ElmRowMajor);
+        intermediate.getMemberAlignment(*memberList[lastIndex].type, lastMemberSize, dummyStride,
+                                        blockType.getQualifier().layoutPacking,
+                                        blockType.getQualifier().layoutMatrix == ElmRowMajor);
 
         return lastOffset + lastMemberSize;
     }
diff --git a/gtests/Spv.FromFile.cpp b/gtests/Spv.FromFile.cpp
index bc05eed..410f8ed 100644
--- a/gtests/Spv.FromFile.cpp
+++ b/gtests/Spv.FromFile.cpp
@@ -309,6 +309,8 @@
         "spv.sampleId.frag",
         "spv.samplePosition.frag",
         "spv.sampleMaskOverrideCoverage.frag",
+        "spv.scalarlayout.frag",
+        "spv.scalarlayoutfloat16.frag",
         "spv.shaderBallot.comp",
         "spv.shaderDrawParams.vert",
         "spv.shaderGroupVote.comp",
diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp
index ac29432..11a7965 100755
--- a/hlsl/hlslParseHelper.cpp
+++ b/hlsl/hlslParseHelper.cpp
@@ -3477,8 +3477,8 @@
             if (argStride != nullptr) {
                 int size;
                 int stride;
-                intermediate.getBaseAlignment(argArray->getType(), size, stride, false,
-                                              argArray->getType().getQualifier().layoutMatrix == ElmRowMajor);
+                intermediate.getMemberAlignment(argArray->getType(), size, stride, argArray->getType().getQualifier().layoutPacking,
+                                                argArray->getType().getQualifier().layoutMatrix == ElmRowMajor);
 
                 TIntermTyped* assign = intermediate.addAssign(EOpAssign, argStride,
                                                               intermediate.addConstantUnion(stride, loc, true), loc);
@@ -8679,7 +8679,7 @@
 {
     if (! qualifier.isUniformOrBuffer())
         return;
-    if (qualifier.layoutPacking != ElpStd140 && qualifier.layoutPacking != ElpStd430)
+    if (qualifier.layoutPacking != ElpStd140 && qualifier.layoutPacking != ElpStd430 && qualifier.layoutPacking != ElpScalar)
         return;
 
     int offset = 0;
@@ -8693,11 +8693,11 @@
         // modify just the children's view of matrix layout, if there is one for this member
         TLayoutMatrix subMatrixLayout = typeList[member].type->getQualifier().layoutMatrix;
         int dummyStride;
-        int memberAlignment = intermediate.getBaseAlignment(*typeList[member].type, memberSize, dummyStride,
-                                                            qualifier.layoutPacking == ElpStd140,
-                                                            subMatrixLayout != ElmNone
-                                                                ? subMatrixLayout == ElmRowMajor
-                                                                : qualifier.layoutMatrix == ElmRowMajor);
+        int memberAlignment = intermediate.getMemberAlignment(*typeList[member].type, memberSize, dummyStride,
+                                                              qualifier.layoutPacking,
+                                                              subMatrixLayout != ElmNone
+                                                                  ? subMatrixLayout == ElmRowMajor
+                                                                  : qualifier.layoutMatrix == ElmRowMajor);
         if (memberQualifier.hasOffset()) {
             // "The specified offset must be a multiple
             // of the base alignment of the type of the block member it qualifies, or a compile-time error results."