浏览代码

[spirv] Implement relaxed layout for vector types (#1092)

Based on GLSL std140/std430 layout rules, relaxed layout allows
using vector's element type's alignment as the vector types's
alignment, so that we can pack a float value and a float3 value
tightly. This is the default right now.

Also add an option, -fvk-use-glsl-layout, to turn off the relaxed
layout for vectors and use conventional GLSL std140/std430 layout
rules.
Lei Zhang 7 年之前
父节点
当前提交
70990344ed

+ 30 - 16
docs/SPIR-V.rst

@@ -555,18 +555,30 @@ Please see the following sections for the details of each type. As a summary:
 =========================== ================== ========================== ==================== =================
 =========================== ================== ========================== ==================== =================
          HLSL Type          Vulkan Buffer Type Default Memory Layout Rule SPIR-V Storage Class SPIR-V Decoration
          HLSL Type          Vulkan Buffer Type Default Memory Layout Rule SPIR-V Storage Class SPIR-V Decoration
 =========================== ================== ========================== ==================== =================
 =========================== ================== ========================== ==================== =================
-``cbuffer``                   Uniform Buffer      GLSL ``std140``            ``Uniform``        ``Block``
-``ConstantBuffer``            Uniform Buffer      GLSL ``std140``            ``Uniform``        ``Block``
-``tbuffer``                   Storage Buffer      GLSL ``std430``            ``Uniform``        ``BufferBlock``
-``TextureBuffer``             Storage Buffer      GLSL ``std430``            ``Uniform``        ``BufferBlock``
-``StructuredBuffer``          Storage Buffer      GLSL ``std430``            ``Uniform``        ``BufferBlock``
-``RWStructuredBuffer``        Storage Buffer      GLSL ``std430``            ``Uniform``        ``BufferBlock``
-``AppendStructuredBuffer``    Storage Buffer      GLSL ``std430``            ``Uniform``        ``BufferBlock``
-``ConsumeStructuredBuffer``   Storage Buffer      GLSL ``std430``            ``Uniform``        ``BufferBlock``
-``ByteAddressBuffer``         Storage Buffer      GLSL ``std430``            ``Uniform``        ``BufferBlock``
-``RWByteAddressBuffer``       Storage Buffer      GLSL ``std430``            ``Uniform``        ``BufferBlock``
+``cbuffer``                   Uniform Buffer    Relaxed GLSL ``std140``      ``Uniform``        ``Block``
+``ConstantBuffer``            Uniform Buffer    Relaxed GLSL ``std140``      ``Uniform``        ``Block``
+``tbuffer``                   Storage Buffer    Relaxed GLSL ``std430``      ``Uniform``        ``BufferBlock``
+``TextureBuffer``             Storage Buffer    Relaxed GLSL ``std430``      ``Uniform``        ``BufferBlock``
+``StructuredBuffer``          Storage Buffer    Relaxed GLSL ``std430``      ``Uniform``        ``BufferBlock``
+``RWStructuredBuffer``        Storage Buffer    Relaxed GLSL ``std430``      ``Uniform``        ``BufferBlock``
+``AppendStructuredBuffer``    Storage Buffer    Relaxed GLSL ``std430``      ``Uniform``        ``BufferBlock``
+``ConsumeStructuredBuffer``   Storage Buffer    Relaxed GLSL ``std430``      ``Uniform``        ``BufferBlock``
+``ByteAddressBuffer``         Storage Buffer    Relaxed GLSL ``std430``      ``Uniform``        ``BufferBlock``
+``RWByteAddressBuffer``       Storage Buffer    Relaxed GLSL ``std430``      ``Uniform``        ``BufferBlock``
 =========================== ================== ========================== ==================== =================
 =========================== ================== ========================== ==================== =================
 
 
+In the above, "relaxed" GLSL ``std140``/``std430`` rules mean GLSL
+``std140``/``std430`` rules with the following modification for vector type
+alignment:
+
+1. The alignment of a vector type is set to be the alignment of its element type
+2. If the above causes an improper straddle (see Vulkan spec
+   `14.5.4. Offset and Stride Assignment <https://www.khronos.org/registry/vulkan/specs/1.0-extensions/html/vkspec.html#interfaces-resources-layout>`_),
+   the alignment will be set to 16 bytes.
+
+To use the conventional GLSL ``std140``/``std430`` rules for resources,
+you can use the ``-fvk-use-glsl-layout`` option.
+
 To know more about the Vulkan buffer types, please refer to the Vulkan spec
 To know more about the Vulkan buffer types, please refer to the Vulkan spec
 `13.1 Descriptor Types <https://www.khronos.org/registry/vulkan/specs/1.0-wsi_extensions/html/vkspec.html#descriptorsets-types>`_.
 `13.1 Descriptor Types <https://www.khronos.org/registry/vulkan/specs/1.0-wsi_extensions/html/vkspec.html#descriptorsets-types>`_.
 
 
@@ -577,8 +589,8 @@ These two buffer types are treated as uniform buffers using Vulkan's
 terminology. They are translated into an ``OpTypeStruct`` with the
 terminology. They are translated into an ``OpTypeStruct`` with the
 necessary layout decorations (``Offset``, ``ArrayStride``, ``MatrixStride``,
 necessary layout decorations (``Offset``, ``ArrayStride``, ``MatrixStride``,
 ``RowMajor``, ``ColMajor``) and the ``Block`` decoration. The layout rule
 ``RowMajor``, ``ColMajor``) and the ``Block`` decoration. The layout rule
-used is GLSL ``std140`` (by default). A variable declared as one of these
-types will be placed in the ``Uniform`` storage class.
+used is relaxed GLSL ``std140`` (by default). A variable declared as one of
+these types will be placed in the ``Uniform`` storage class.
 
 
 For example, for the following HLSL source code:
 For example, for the following HLSL source code:
 
 
@@ -616,8 +628,8 @@ terminology. They are translated into an ``OpTypeStruct`` with the
 necessary layout decorations (``Offset``, ``ArrayStride``, ``MatrixStride``,
 necessary layout decorations (``Offset``, ``ArrayStride``, ``MatrixStride``,
 ``RowMajor``, ``ColMajor``) and the ``BufferBlock`` decoration. All the struct
 ``RowMajor``, ``ColMajor``) and the ``BufferBlock`` decoration. All the struct
 members are also decorated with ``NonWritable`` decoration. The layout rule
 members are also decorated with ``NonWritable`` decoration. The layout rule
-used is GLSL ``std430`` (by default). A variable declared as one of these
-types will be placed in the ``Uniform`` storage class.
+used is relaxed GLSL ``std430`` (by default). A variable declared as one of
+these types will be placed in the ``Uniform`` storage class.
 
 
 
 
 ``StructuredBuffer`` and ``RWStructuredBuffer``
 ``StructuredBuffer`` and ``RWStructuredBuffer``
@@ -627,7 +639,7 @@ types will be placed in the ``Uniform`` storage class.
 using Vulkan's terminology. It is translated into an ``OpTypeStruct`` containing
 using Vulkan's terminology. It is translated into an ``OpTypeStruct`` containing
 an ``OpTypeRuntimeArray`` of type ``T``, with necessary layout decorations
 an ``OpTypeRuntimeArray`` of type ``T``, with necessary layout decorations
 (``Offset``, ``ArrayStride``, ``MatrixStride``, ``RowMajor``, ``ColMajor``) and
 (``Offset``, ``ArrayStride``, ``MatrixStride``, ``RowMajor``, ``ColMajor``) and
-the ``BufferBlock`` decoration.  The default layout rule used is GLSL
+the ``BufferBlock`` decoration.  The default layout rule used is relaxed GLSL
 ``std430``. A variable declared as one of these types will be placed in the
 ``std430``. A variable declared as one of these types will be placed in the
 ``Uniform`` storage class.
 ``Uniform`` storage class.
 
 
@@ -678,7 +690,7 @@ storage buffer using Vulkan's terminology. It is translated into an
 ``OpTypeStruct`` containing an ``OpTypeRuntimeArray`` of type ``T``, with
 ``OpTypeStruct`` containing an ``OpTypeRuntimeArray`` of type ``T``, with
 necessary layout decorations (``Offset``, ``ArrayStride``, ``MatrixStride``,
 necessary layout decorations (``Offset``, ``ArrayStride``, ``MatrixStride``,
 ``RowMajor``, ``ColMajor``) and the ``BufferBlock`` decoration. The default
 ``RowMajor``, ``ColMajor``) and the ``BufferBlock`` decoration. The default
-layout rule used is GLSL ``std430``.
+layout rule used is relaxed GLSL ``std430``.
 
 
 A variable declared as one of these types will be placed in the ``Uniform``
 A variable declared as one of these types will be placed in the ``Uniform``
 storage class. Besides, each variable will have an associated counter variable
 storage class. Besides, each variable will have an associated counter variable
@@ -2519,6 +2531,8 @@ codegen for Vulkan:
 - ``-fvk-ignore-unused-resources``: Avoids emitting SPIR-V code for resources
 - ``-fvk-ignore-unused-resources``: Avoids emitting SPIR-V code for resources
   defined but not statically referenced by the call tree of the entry point
   defined but not statically referenced by the call tree of the entry point
   in question.
   in question.
+- ``-fvk-use-glsl-layout``: Uses conventional GLSL ``std140``/``std430`` layout
+  rules for resources.
 - ``-fvk-invert-y``: Inverts SV_Position.y before writing to stage output.
 - ``-fvk-invert-y``: Inverts SV_Position.y before writing to stage output.
   Used to accommodate the difference between Vulkan's coordinate system and
   Used to accommodate the difference between Vulkan's coordinate system and
   DirectX's. Only allowed in VS/DS/GS.
   DirectX's. Only allowed in VS/DS/GS.

+ 1 - 0
include/dxc/Support/HLSLOptions.h

@@ -162,6 +162,7 @@ public:
   bool GenSPIRV; // OPT_spirv
   bool GenSPIRV; // OPT_spirv
   bool VkIgnoreUnusedResources; // OPT_fvk_ignore_used_resources
   bool VkIgnoreUnusedResources; // OPT_fvk_ignore_used_resources
   bool VkInvertY; // OPT_fvk_invert_y
   bool VkInvertY; // OPT_fvk_invert_y
+  bool VkUseGlslLayout; // OPT_fvk_use_glsl_layout
   llvm::StringRef VkStageIoOrder; // OPT_fvk_stage_io_order
   llvm::StringRef VkStageIoOrder; // OPT_fvk_stage_io_order
   llvm::SmallVector<uint32_t, 4> VkBShift; // OPT_fvk_b_shift
   llvm::SmallVector<uint32_t, 4> VkBShift; // OPT_fvk_b_shift
   llvm::SmallVector<uint32_t, 4> VkTShift; // OPT_fvk_t_shift
   llvm::SmallVector<uint32_t, 4> VkTShift; // OPT_fvk_t_shift

+ 2 - 0
include/dxc/Support/HLSLOptions.td

@@ -250,6 +250,8 @@ def fvk_u_shift : MultiArg<["-"], "fvk-u-shift", 2>, MetaVarName<"<shift> <space
   HelpText<"Specify Vulkan binding number shift for u-type register">;
   HelpText<"Specify Vulkan binding number shift for u-type register">;
 def fvk_invert_y: Flag<["-"], "fvk-invert-y">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
 def fvk_invert_y: Flag<["-"], "fvk-invert-y">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
   HelpText<"Invert SV_Position.y in VS/DS/GS to accommodate Vulkan's coordinate system">;
   HelpText<"Invert SV_Position.y in VS/DS/GS to accommodate Vulkan's coordinate system">;
+def fvk_use_glsl_layout: Flag<["-"], "fvk-use-glsl-layout">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
+  HelpText<"Use conventional GLSL std140/std430 layout for resources">;
 // SPIRV Change Ends
 // SPIRV Change Ends
 
 
 //////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////

+ 2 - 0
lib/DxcSupport/HLSLOptions.cpp

@@ -483,6 +483,7 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
 #ifdef ENABLE_SPIRV_CODEGEN
 #ifdef ENABLE_SPIRV_CODEGEN
   const bool genSpirv = opts.GenSPIRV = Args.hasFlag(OPT_spirv, OPT_INVALID, false);
   const bool genSpirv = opts.GenSPIRV = Args.hasFlag(OPT_spirv, OPT_INVALID, false);
   opts.VkInvertY = Args.hasFlag(OPT_fvk_invert_y, OPT_INVALID, false);
   opts.VkInvertY = Args.hasFlag(OPT_fvk_invert_y, OPT_INVALID, false);
+  opts.VkUseGlslLayout = Args.hasFlag(OPT_fvk_use_glsl_layout, OPT_INVALID, false);
   opts.VkIgnoreUnusedResources = Args.hasFlag(OPT_fvk_ignore_unused_resources, OPT_INVALID, false);
   opts.VkIgnoreUnusedResources = Args.hasFlag(OPT_fvk_ignore_unused_resources, OPT_INVALID, false);
 
 
   // Collects the arguments for -fvk-{b|s|t|u}-shift.
   // Collects the arguments for -fvk-{b|s|t|u}-shift.
@@ -522,6 +523,7 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
 #else
 #else
   if (Args.hasFlag(OPT_spirv, OPT_INVALID, false) ||
   if (Args.hasFlag(OPT_spirv, OPT_INVALID, false) ||
       Args.hasFlag(OPT_fvk_invert_y, OPT_INVALID, false) ||
       Args.hasFlag(OPT_fvk_invert_y, OPT_INVALID, false) ||
+      Args.hasFlag(OPT_fvk_use_glsl_layout, OPT_INVALID, false) ||
       Args.hasFlag(OPT_fvk_ignore_unused_resources, OPT_INVALID, false) ||
       Args.hasFlag(OPT_fvk_ignore_unused_resources, OPT_INVALID, false) ||
       !Args.getLastArgValue(OPT_fvk_stage_io_order_EQ).empty() ||
       !Args.getLastArgValue(OPT_fvk_stage_io_order_EQ).empty() ||
       !Args.getLastArgValue(OPT_fvk_b_shift).empty() ||
       !Args.getLastArgValue(OPT_fvk_b_shift).empty() ||

+ 1 - 0
tools/clang/include/clang/SPIRV/EmitSPIRVOptions.h

@@ -20,6 +20,7 @@ struct EmitSPIRVOptions {
   bool defaultRowMajor;
   bool defaultRowMajor;
   bool disableValidation;
   bool disableValidation;
   bool invertY;
   bool invertY;
+  bool useGlslLayout;
   bool ignoreUnusedResources;
   bool ignoreUnusedResources;
   bool enable16BitTypes;
   bool enable16BitTypes;
   llvm::StringRef stageIoOrder;
   llvm::StringRef stageIoOrder;

+ 50 - 6
tools/clang/lib/SPIRV/TypeTranslator.cpp

@@ -32,6 +32,15 @@ inline void roundToPow2(uint32_t *val, uint32_t pow2) {
   assert(pow2 != 0);
   assert(pow2 != 0);
   *val = (*val + pow2 - 1) & ~(pow2 - 1);
   *val = (*val + pow2 - 1) & ~(pow2 - 1);
 }
 }
+
+/// Returns true if the given vector type (of the given size) crosses the
+/// 4-component vector boundary if placed at the given offset.
+bool improperStraddle(QualType type, int size, int offset) {
+  assert(TypeTranslator::isVectorType(type));
+  return size <= 16 ? offset / 16 != (offset + size - 1) / 16
+                    : offset % 16 != 0;
+}
+
 } // anonymous namespace
 } // anonymous namespace
 
 
 bool TypeTranslator::isRelaxedPrecisionType(QualType type,
 bool TypeTranslator::isRelaxedPrecisionType(QualType type,
@@ -1079,11 +1088,13 @@ TypeTranslator::getLayoutDecorations(const DeclContext *decl, LayoutRule rule) {
     std::tie(memberAlignment, memberSize) =
     std::tie(memberAlignment, memberSize) =
         getAlignmentAndSize(fieldType, rule, isRowMajor, &stride);
         getAlignmentAndSize(fieldType, rule, isRowMajor, &stride);
 
 
+    alignUsingHLSLRelaxedLayout(fieldType, memberSize, &memberAlignment,
+                                &offset);
+
     // Each structure-type member must have an Offset Decoration.
     // Each structure-type member must have an Offset Decoration.
     if (const auto *offsetAttr = field->getAttr<VKOffsetAttr>())
     if (const auto *offsetAttr = field->getAttr<VKOffsetAttr>())
       offset = offsetAttr->getOffset();
       offset = offsetAttr->getOffset();
-    else
-      roundToPow2(&offset, memberAlignment);
+
     decorations.push_back(Decoration::getOffset(*spirvContext, offset, index));
     decorations.push_back(Decoration::getOffset(*spirvContext, offset, index));
     offset += memberSize;
     offset += memberSize;
 
 
@@ -1330,6 +1341,37 @@ TypeTranslator::translateSampledTypeToImageFormat(QualType sampledType) {
   return spv::ImageFormat::Unknown;
   return spv::ImageFormat::Unknown;
 }
 }
 
 
+void TypeTranslator::alignUsingHLSLRelaxedLayout(QualType fieldType,
+                                                 uint32_t fieldSize,
+                                                 uint32_t *fieldAlignment,
+                                                 uint32_t *currentOffset) {
+  bool fieldIsVecType = false;
+
+  if (!spirvOptions.useGlslLayout) {
+    // Adjust according to HLSL relaxed layout rules.
+    // Aligning vectors as their element types so that we can pack a float
+    // and a float3 tightly together.
+    QualType vecElemType = {};
+    if (fieldIsVecType = isVectorType(fieldType, &vecElemType)) {
+      uint32_t scalarAlignment = 0;
+      std::tie(scalarAlignment, std::ignore) =
+          getAlignmentAndSize(vecElemType, LayoutRule::Void, false, nullptr);
+      if (scalarAlignment <= 4)
+        *fieldAlignment = scalarAlignment;
+    }
+  }
+
+  roundToPow2(currentOffset, *fieldAlignment);
+
+  // Adjust according to HLSL relaxed layout rules.
+  // Bump to 4-component vector alignment if there is a bad straddle
+  if (!spirvOptions.useGlslLayout && fieldIsVecType &&
+      improperStraddle(fieldType, fieldSize, *currentOffset)) {
+    *fieldAlignment = kStd140Vec4Alignment;
+    roundToPow2(currentOffset, *fieldAlignment);
+  }
+}
+
 std::pair<uint32_t, uint32_t>
 std::pair<uint32_t, uint32_t>
 TypeTranslator::getAlignmentAndSize(QualType type, LayoutRule rule,
 TypeTranslator::getAlignmentAndSize(QualType type, LayoutRule rule,
                                     const bool isRowMajor, uint32_t *stride) {
                                     const bool isRowMajor, uint32_t *stride) {
@@ -1405,8 +1447,8 @@ TypeTranslator::getAlignmentAndSize(QualType type, LayoutRule rule,
         case BuiltinType::ULongLong:
         case BuiltinType::ULongLong:
           return {8, 8};
           return {8, 8};
         default:
         default:
-          emitError("primitive type %0 unimplemented")
-              << builtinType->getTypeClassName();
+          emitError("alignment and size calculation for type %0 unimplemented")
+              << type;
           return {0, 0};
           return {0, 0};
         }
         }
   }
   }
@@ -1463,10 +1505,12 @@ TypeTranslator::getAlignmentAndSize(QualType type, LayoutRule rule,
       std::tie(memberAlignment, memberSize) =
       std::tie(memberAlignment, memberSize) =
           getAlignmentAndSize(field->getType(), rule, isRowMajor, stride);
           getAlignmentAndSize(field->getType(), rule, isRowMajor, stride);
 
 
+      alignUsingHLSLRelaxedLayout(field->getType(), memberSize,
+                                  &memberAlignment, &structSize);
+
       // The base alignment of the structure is N, where N is the largest
       // The base alignment of the structure is N, where N is the largest
       // base alignment value of any of its members...
       // base alignment value of any of its members...
       maxAlignment = std::max(maxAlignment, memberAlignment);
       maxAlignment = std::max(maxAlignment, memberAlignment);
-      roundToPow2(&structSize, memberAlignment);
       structSize += memberSize;
       structSize += memberSize;
     }
     }
 
 
@@ -1504,7 +1548,7 @@ TypeTranslator::getAlignmentAndSize(QualType type, LayoutRule rule,
     return {alignment, size};
     return {alignment, size};
   }
   }
 
 
-  emitError("type %0 unimplemented") << type->getTypeClassName();
+  emitError("alignment and size calculation for type %0 unimplemented") << type;
   return {0, 0};
   return {0, 0};
 }
 }
 
 

+ 10 - 1
tools/clang/lib/SPIRV/TypeTranslator.h

@@ -261,10 +261,19 @@ private:
   /// instructions and returns the <result-id>. Returns 0 on failure.
   /// instructions and returns the <result-id>. Returns 0 on failure.
   uint32_t translateResourceType(QualType type, LayoutRule rule);
   uint32_t translateResourceType(QualType type, LayoutRule rule);
 
 
-  /// \bried For the given sampled type, returns the corresponding image format
+  /// \brief For the given sampled type, returns the corresponding image format
   /// that can be used to create an image object.
   /// that can be used to create an image object.
   spv::ImageFormat translateSampledTypeToImageFormat(QualType type);
   spv::ImageFormat translateSampledTypeToImageFormat(QualType type);
 
 
+  /// \brief Aligns currentOffset properly to allow packing vectors in the HLSL
+  /// way: using the element type's alignment as the vector alignment, as long
+  /// as there is no improper straddle.
+  /// fieldSize and fieldAlignment are the original size and alignment
+  /// calculated without considering the HLSL vector relaxed rule.
+  void alignUsingHLSLRelaxedLayout(QualType fieldType, uint32_t fieldSize,
+                                   uint32_t *fieldAlignment,
+                                   uint32_t *currentOffset);
+
 public:
 public:
   /// \brief Returns the alignment and size in bytes for the given type
   /// \brief Returns the alignment and size in bytes for the given type
   /// according to the given LayoutRule.
   /// according to the given LayoutRule.

+ 1 - 1
tools/clang/test/CodeGenSPIRV/method.append-structured-buffer.get-dimensions.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T vs_6_0 -E main
+// Run: %dxc -T vs_6_0 -E main -fvk-use-glsl-layout
 
 
 struct S {
 struct S {
     float a;
     float a;

+ 1 - 1
tools/clang/test/CodeGenSPIRV/method.consume-structured-buffer.get-dimensions.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T vs_6_0 -E main
+// Run: %dxc -T vs_6_0 -E main -fvk-use-glsl-layout
 
 
 struct S {
 struct S {
     float a;
     float a;

+ 1 - 1
tools/clang/test/CodeGenSPIRV/method.structured-buffer.get-dimensions.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T ps_6_0 -E main
+// Run: %dxc -T ps_6_0 -E main -fvk-use-glsl-layout
 
 
 struct SBuffer {
 struct SBuffer {
   float4   f1;
   float4   f1;

+ 1 - 1
tools/clang/test/CodeGenSPIRV/vk.layout.cbuffer.std140.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T vs_6_0 -E main
+// Run: %dxc -T vs_6_0 -E main -fvk-use-glsl-layout
 
 
 struct R {     // Alignment                           Offset     Size       Next
 struct R {     // Alignment                           Offset     Size       Next
     float2 rf; // 8(vec2)                          -> 0        + 8(vec2)  = 8
     float2 rf; // 8(vec2)                          -> 0        + 8(vec2)  = 8

+ 1 - 1
tools/clang/test/CodeGenSPIRV/vk.layout.push-constant.std430.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T vs_6_0 -E main
+// Run: %dxc -T vs_6_0 -E main -fvk-use-glsl-layout
 
 
 // CHECK: OpDecorate %_arr_v2float_uint_3 ArrayStride 8
 // CHECK: OpDecorate %_arr_v2float_uint_3 ArrayStride 8
 // CHECK: OpDecorate %_arr_mat3v2float_uint_2 ArrayStride 32
 // CHECK: OpDecorate %_arr_mat3v2float_uint_2 ArrayStride 32

+ 1 - 1
tools/clang/test/CodeGenSPIRV/vk.layout.sbuffer.std430.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T ps_6_0 -E main
+// Run: %dxc -T ps_6_0 -E main -fvk-use-glsl-layout
 
 
 struct R {     // Alignment       Offset     Size       Next
 struct R {     // Alignment       Offset     Size       Next
     float2 rf; // 8(vec2)      -> 0        + 8(vec2)  = 8
     float2 rf; // 8(vec2)      -> 0        + 8(vec2)  = 8

+ 124 - 0
tools/clang/test/CodeGenSPIRV/vk.layout.vector.relaxed.hlsl

@@ -0,0 +1,124 @@
+// Run: %dxc -T ps_6_0 -E main
+
+    // For ConstantBuffer & cbuffer
+// CHECK: OpMemberDecorate %S 0 Offset 0
+// CHECK: OpMemberDecorate %S 1 Offset 4
+// CHECK: OpMemberDecorate %S 2 Offset 16
+// CHECK: OpMemberDecorate %S 3 Offset 28
+// CHECK: OpMemberDecorate %S 4 Offset 32
+// CHECK: OpMemberDecorate %S 5 Offset 36
+// CHECK: OpMemberDecorate %S 6 Offset 44
+// CHECK: OpMemberDecorate %S 7 Offset 48
+// CHECK: OpMemberDecorate %S 8 Offset 56
+// CHECK: OpMemberDecorate %S 9 Offset 64
+// CHECK: OpMemberDecorate %S 10 Offset 80
+// CHECK: OpMemberDecorate %S 11 Offset 92
+// CHECK: OpMemberDecorate %S 12 Offset 96
+// CHECK: OpMemberDecorate %S 13 Offset 112
+// CHECK: OpMemberDecorate %S 14 Offset 128
+// CHECK: OpMemberDecorate %S 15 Offset 140
+// CHECK: OpMemberDecorate %S 16 Offset 144
+// CHECK: OpMemberDecorate %S 17 Offset 160
+// CHECK: OpMemberDecorate %S 18 Offset 176
+// CHECK: OpMemberDecorate %S 19 Offset 192
+// CHECK: OpMemberDecorate %S 20 Offset 208
+// CHECK: OpMemberDecorate %S 21 Offset 240
+// CHECK: OpMemberDecorate %S 22 Offset 272
+// CHECK: OpMemberDecorate %S 23 Offset 304
+
+    // For StructuredBuffer & tbuffer
+// CHECK: OpMemberDecorate %S_0 0 Offset 0
+// CHECK: OpMemberDecorate %S_0 1 Offset 4
+// CHECK: OpMemberDecorate %S_0 2 Offset 16
+// CHECK: OpMemberDecorate %S_0 3 Offset 28
+// CHECK: OpMemberDecorate %S_0 4 Offset 32
+// CHECK: OpMemberDecorate %S_0 5 Offset 36
+// CHECK: OpMemberDecorate %S_0 6 Offset 44
+// CHECK: OpMemberDecorate %S_0 7 Offset 48
+// CHECK: OpMemberDecorate %S_0 8 Offset 56
+// CHECK: OpMemberDecorate %S_0 9 Offset 64
+// CHECK: OpMemberDecorate %S_0 10 Offset 80
+// CHECK: OpMemberDecorate %S_0 11 Offset 92
+// CHECK: OpMemberDecorate %S_0 12 Offset 96
+// CHECK: OpMemberDecorate %S_0 13 Offset 112
+// CHECK: OpMemberDecorate %S_0 14 Offset 128
+// CHECK: OpMemberDecorate %S_0 15 Offset 140
+// CHECK: OpMemberDecorate %S_0 16 Offset 144
+// CHECK: OpMemberDecorate %S_0 17 Offset 160
+// CHECK: OpMemberDecorate %S_0 18 Offset 176
+// CHECK: OpMemberDecorate %S_0 19 Offset 192
+// CHECK: OpMemberDecorate %S_0 20 Offset 196
+// CHECK: OpMemberDecorate %S_0 21 Offset 208
+// CHECK: OpMemberDecorate %S_0 22 Offset 240
+// CHECK: OpMemberDecorate %S_0 23 Offset 272
+
+// CHECK: OpDecorate %_runtimearr_T ArrayStride 288
+
+// CHECK:     %type_ConstantBuffer_T = OpTypeStruct %S
+// CHECK:                         %T = OpTypeStruct %S_0
+// CHECK:   %type_StructuredBuffer_T = OpTypeStruct %_runtimearr_T
+// CHECK: %type_RWStructuredBuffer_T = OpTypeStruct %_runtimearr_T
+// CHECK:              %type_TBuffer = OpTypeStruct %S_0
+
+// CHECK:   %MyCBuffer = OpVariable %_ptr_Uniform_type_ConstantBuffer_T Uniform
+// CHECK:   %MySBuffer = OpVariable %_ptr_Uniform_type_StructuredBuffer_T Uniform
+// CHECK: %MyRWSBuffer = OpVariable %_ptr_Uniform_type_RWStructuredBuffer_T Uniform
+// CHECK:     %CBuffer = OpVariable %_ptr_Uniform_type_ConstantBuffer_T Uniform
+// CHECK:     %TBuffer = OpVariable %_ptr_Uniform_type_TBuffer Uniform
+
+struct S {
+    float  f0;
+    float3 f1;
+
+    float3 f2;
+    float1 f3;
+
+    float  f4;
+    float2 f5;
+    float1 f6;
+
+    float2 f7;
+    float2 f8;
+
+    float2 f9;
+    float3 f10;
+    float  f11;
+
+    float1 f12;
+    float4 f13;
+    float3 f14;
+    float  f15;
+
+    float1 f16[1];
+    float3 f17[1];
+
+    float3 f18[1];
+    float  f19[1];
+
+    float1 f20[2];
+    float3 f21[2];
+
+    float3 f22[2];
+    float  f23[2];
+};
+
+struct T {
+    S s;
+};
+
+
+    ConstantBuffer<T> MyCBuffer;
+  StructuredBuffer<T> MySBuffer;
+RWStructuredBuffer<T> MyRWSBuffer;
+
+cbuffer CBuffer {
+    S CB_s;
+};
+
+tbuffer TBuffer {
+    S TB_s;
+};
+
+float4 main() : SV_Target {
+    return MyCBuffer.s.f0 + MySBuffer[0].s.f4 + CB_s.f11 + TB_s.f15;
+}

+ 1 - 0
tools/clang/tools/dxcompiler/dxcompilerobj.cpp

@@ -469,6 +469,7 @@ public:
           spirvOpts.codeGenHighLevel = opts.CodeGenHighLevel;
           spirvOpts.codeGenHighLevel = opts.CodeGenHighLevel;
           spirvOpts.disableValidation = opts.DisableValidation;
           spirvOpts.disableValidation = opts.DisableValidation;
           spirvOpts.invertY = opts.VkInvertY;
           spirvOpts.invertY = opts.VkInvertY;
+          spirvOpts.useGlslLayout = opts.VkUseGlslLayout;
           spirvOpts.ignoreUnusedResources = opts.VkIgnoreUnusedResources;
           spirvOpts.ignoreUnusedResources = opts.VkIgnoreUnusedResources;
           spirvOpts.defaultRowMajor = opts.DefaultRowMajor;
           spirvOpts.defaultRowMajor = opts.DefaultRowMajor;
           spirvOpts.stageIoOrder = opts.VkStageIoOrder;
           spirvOpts.stageIoOrder = opts.VkStageIoOrder;

+ 5 - 0
tools/clang/unittests/SPIRV/CodeGenSPIRVTest.cpp

@@ -1217,6 +1217,11 @@ TEST_F(FileTest, VulkanLayout64BitTypesStd430) {
 TEST_F(FileTest, VulkanLayout64BitTypesStd140) {
 TEST_F(FileTest, VulkanLayout64BitTypesStd140) {
   runFileTest("vk.layout.64bit-types.std140.hlsl");
   runFileTest("vk.layout.64bit-types.std140.hlsl");
 }
 }
+TEST_F(FileTest, VulkanLayoutVectorRelaxedLayout) {
+  // Allows vectors to be aligned according to their element types, if not
+  // causing improper straddle
+  runFileTest("vk.layout.vector.relaxed.hlsl");
+}
 
 
 TEST_F(FileTest, VulkanLayoutPushConstantStd430) {
 TEST_F(FileTest, VulkanLayoutPushConstantStd430) {
   runFileTest("vk.layout.push-constant.std430.hlsl");
   runFileTest("vk.layout.push-constant.std430.hlsl");