Explorar el Código

[spirv] Add support for DX layout rules (#1198)

These layout rules can be turned on with -fvk-use-dx-layout.
For both cbuffer/tbuffer and structured buffers.
Lei Zhang hace 7 años
padre
commit
99c142be0b

+ 6 - 2
docs/SPIR-V.rst

@@ -311,7 +311,7 @@ in the CodeGen using the **explicit** mode, turned on by the
 ``-fspv-extension=<extension>`` command-line option. Only extensions supplied
 via ``-fspv-extension=`` will be used. If that does not suffice, errors will
 be emitted explaining what additional extensions are required to translate what
-specific feature in the source code. If you want to allow all KHR extensions, 
+specific feature in the source code. If you want to allow all KHR extensions,
 you can use ``-fspv-extension=KHR``.
 
 Legalization, optimization, validation
@@ -662,7 +662,10 @@ alignment:
    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.
+specify the ``-fvk-use-glsl-layout`` option.
+
+To use the same layout rules as DirectX, specify the ``-fvk-dx-layout``
+option.
 
 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>`_.
@@ -2644,6 +2647,7 @@ codegen for Vulkan:
   in question.
 - ``-fvk-use-glsl-layout``: Uses conventional GLSL ``std140``/``std430`` layout
   rules for resources.
+- ``-fvk-use-dx-layout``: Uses DirectX layout rules for resources.
 - ``-fvk-invert-y``: Inverts SV_Position.y before writing to stage output.
   Used to accommodate the difference between Vulkan's coordinate system and
   DirectX's. Only allowed in VS/DS/GS.

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

@@ -164,6 +164,7 @@ public:
   bool VkIgnoreUnusedResources;            // OPT_fvk_ignore_used_resources
   bool VkInvertY;                          // OPT_fvk_invert_y
   bool VkUseGlslLayout;                    // OPT_fvk_use_glsl_layout
+  bool VkUseDxLayout;                      // OPT_fvk_use_dx_layout
   bool SpvEnableReflect;                   // OPT_fspv_reflect
   llvm::StringRef VkStageIoOrder;          // OPT_fvk_stage_io_order
   llvm::SmallVector<uint32_t, 4> VkBShift; // OPT_fvk_b_shift

+ 3 - 1
include/dxc/Support/HLSLOptions.td

@@ -251,7 +251,9 @@ def fvk_u_shift : MultiArg<["-"], "fvk-u-shift", 2>, MetaVarName<"<shift> <space
 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">;
 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">;
+  HelpText<"Use conventional GLSL std140/std430 memory layout for Vulkan resources">;
+def fvk_use_dx_layout: Flag<["-"], "fvk-use-dx-layout">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
+  HelpText<"Use DirectX memory layout for Vulkan resources">;
 def fspv_reflect: Flag<["-"], "fspv-reflect">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
   HelpText<"Emit additional SPIR-V instructions to aid reflection">;
 def fspv_extension_EQ : Joined<["-"], "fspv-extension=">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,

+ 2 - 0
lib/DxcSupport/HLSLOptions.cpp

@@ -485,6 +485,7 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
   const bool genSpirv = opts.GenSPIRV = Args.hasFlag(OPT_spirv, 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.VkUseDxLayout = Args.hasFlag(OPT_fvk_use_dx_layout, OPT_INVALID, false);
   opts.SpvEnableReflect = Args.hasFlag(OPT_fspv_reflect, OPT_INVALID, false);
   opts.VkIgnoreUnusedResources = Args.hasFlag(OPT_fvk_ignore_unused_resources, OPT_INVALID, false);
 
@@ -532,6 +533,7 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
   if (Args.hasFlag(OPT_spirv, 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_use_dx_layout, OPT_INVALID, false) ||
       Args.hasFlag(OPT_fspv_reflect, OPT_INVALID, false) ||
       Args.hasFlag(OPT_fvk_ignore_unused_resources, OPT_INVALID, false) ||
       !Args.getLastArgValue(OPT_fvk_stage_io_order_EQ).empty() ||

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

@@ -13,6 +13,19 @@
 #include "llvm/ADT/StringRef.h"
 
 namespace clang {
+namespace spirv {
+/// Memory layout rules
+enum class LayoutRule {
+  Void,
+  GLSLStd140,
+  GLSLStd430,
+  RelaxedGLSLStd140, // std140 with relaxed vector layout
+  RelaxedGLSLStd430, // std430 with relaxed vector layout
+  FxcCTBuffer,       // fxc.exe layout rule for cbuffer/tbuffer
+  FxcSBuffer,        // fxc.exe layout rule for structured buffers
+};
+} // namespace spirv
+
 /// Structs for controlling behaviors of SPIR-V codegen.
 struct EmitSPIRVOptions {
   /// Disable legalization and optimization and emit raw SPIR-V
@@ -21,6 +34,7 @@ struct EmitSPIRVOptions {
   bool disableValidation;
   bool invertY;
   bool useGlslLayout;
+  bool useDxLayout;
   bool ignoreUnusedResources;
   bool enable16BitTypes;
   bool enableReflect;
@@ -31,6 +45,12 @@ struct EmitSPIRVOptions {
   llvm::SmallVector<uint32_t, 4> uShift;
   llvm::SmallVector<llvm::StringRef, 4> allowedExtensions;
   llvm::StringRef targetEnv;
+  spirv::LayoutRule cBufferLayoutRule;
+  spirv::LayoutRule tBufferLayoutRule;
+  spirv::LayoutRule sBufferLayoutRule;
+
+  // Initializes dependent fields appropriately
+  void Initialize();
 };
 } // end namespace clang
 

+ 1 - 0
tools/clang/lib/SPIRV/CMakeLists.txt

@@ -8,6 +8,7 @@ add_clang_library(clangSPIRV
   DeclResultIdMapper.cpp
   Decoration.cpp
   EmitSPIRVAction.cpp
+  EmitSPIRVOptions.cpp
   FeatureManager.cpp
   GlPerVertex.cpp
   InitListHandler.cpp

+ 13 - 11
tools/clang/lib/SPIRV/DeclResultIdMapper.cpp

@@ -402,12 +402,12 @@ SpirvEvalInfo DeclResultIdMapper::createExternVar(const VarDecl *var) {
     if (typeName == "StructuredBuffer" || typeName == "ByteAddressBuffer" ||
         typeName == "RWByteAddressBuffer") {
       storageClass = spv::StorageClass::Uniform;
-      rule = LayoutRule::GLSLStd430;
+      rule = spirvOptions.sBufferLayoutRule;
     } else if (typeName == "RWStructuredBuffer" ||
                typeName == "AppendStructuredBuffer" ||
                typeName == "ConsumeStructuredBuffer") {
       storageClass = spv::StorageClass::Uniform;
-      rule = LayoutRule::GLSLStd430;
+      rule = spirvOptions.sBufferLayoutRule;
       isACRWSBuffer = true;
     }
   } else {
@@ -492,9 +492,11 @@ uint32_t DeclResultIdMapper::createStructOrStructArrayVarOfExplicitLayout(
   const bool forGlobals = usageKind == ContextUsageKind::Globals;
 
   auto &context = *theBuilder.getSPIRVContext();
-  const LayoutRule layoutRule = (forCBuffer || forGlobals)
-                                    ? LayoutRule::GLSLStd140
-                                    : LayoutRule::GLSLStd430;
+  const LayoutRule layoutRule =
+      (forCBuffer || forGlobals)
+          ? spirvOptions.cBufferLayoutRule
+          : (forTBuffer ? spirvOptions.tBufferLayoutRule
+                        : spirvOptions.sBufferLayoutRule);
   const auto *blockDec = forTBuffer ? Decoration::getBufferBlock(context)
                                     : Decoration::getBlock(context);
 
@@ -572,8 +574,8 @@ uint32_t DeclResultIdMapper::createCTBuffer(const HLSLBufferDecl *decl) {
     astDecls[varDecl] =
         SpirvEvalInfo(bufferVar)
             .setStorageClass(spv::StorageClass::Uniform)
-            .setLayoutRule(decl->isCBuffer() ? LayoutRule::GLSLStd140
-                                             : LayoutRule::GLSLStd430);
+            .setLayoutRule(decl->isCBuffer() ? spirvOptions.cBufferLayoutRule
+                                             : spirvOptions.tBufferLayoutRule);
     astDecls[varDecl].indexInCTBuffer = index++;
   }
   resourceVars.emplace_back(
@@ -612,8 +614,8 @@ uint32_t DeclResultIdMapper::createCTBuffer(const VarDecl *decl) {
   astDecls[decl] =
       SpirvEvalInfo(bufferVar)
           .setStorageClass(spv::StorageClass::Uniform)
-          .setLayoutRule(context->isCBuffer() ? LayoutRule::GLSLStd140
-                                              : LayoutRule::GLSLStd430);
+          .setLayoutRule(context->isCBuffer() ? spirvOptions.cBufferLayoutRule
+                                              : spirvOptions.tBufferLayoutRule);
   resourceVars.emplace_back(
       bufferVar, ResourceVar::Category::Other, getResourceBinding(context),
       decl->getAttr<VKBindingAttr>(), decl->getAttr<VKCounterBindingAttr>());
@@ -635,7 +637,7 @@ uint32_t DeclResultIdMapper::createPushConstant(const VarDecl *decl) {
   // Register the VarDecl
   astDecls[decl] = SpirvEvalInfo(var)
                        .setStorageClass(spv::StorageClass::PushConstant)
-                       .setLayoutRule(LayoutRule::GLSLStd430);
+                       .setLayoutRule(spirvOptions.sBufferLayoutRule);
   // Do not push this variable into resourceVars since it does not need
   // descriptor set.
 
@@ -670,7 +672,7 @@ void DeclResultIdMapper::createGlobalsCBuffer(const VarDecl *var) {
 
       astDecls[varDecl] = SpirvEvalInfo(globals)
                               .setStorageClass(spv::StorageClass::Uniform)
-                              .setLayoutRule(LayoutRule::GLSLStd140);
+                              .setLayoutRule(spirvOptions.cBufferLayoutRule);
       astDecls[varDecl].indexInCTBuffer = index++;
     }
 }

+ 29 - 0
tools/clang/lib/SPIRV/EmitSPIRVOptions.cpp

@@ -0,0 +1,29 @@
+//===-- EmitSPIRVOptions.cpp - Options for SPIR-V CodeGen -------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/SPIRV/EmitSPIRVOptions.h"
+
+namespace clang {
+
+void EmitSPIRVOptions::Initialize() {
+  if (useDxLayout) {
+    cBufferLayoutRule = spirv::LayoutRule::FxcCTBuffer;
+    tBufferLayoutRule = spirv::LayoutRule::FxcCTBuffer;
+    sBufferLayoutRule = spirv::LayoutRule::FxcSBuffer;
+  } else if (useGlslLayout) {
+    cBufferLayoutRule = spirv::LayoutRule::GLSLStd140;
+    tBufferLayoutRule = spirv::LayoutRule::GLSLStd430;
+    sBufferLayoutRule = spirv::LayoutRule::GLSLStd430;
+  } else {
+    cBufferLayoutRule = spirv::LayoutRule::RelaxedGLSLStd140;
+    tBufferLayoutRule = spirv::LayoutRule::RelaxedGLSLStd430;
+    sBufferLayoutRule = spirv::LayoutRule::RelaxedGLSLStd430;
+  }
+}
+
+} // end namespace clang

+ 10 - 5
tools/clang/lib/SPIRV/SPIRVEmitter.cpp

@@ -512,8 +512,7 @@ spv::Capability getCapabilityForGroupNonUniform(spv::Op opcode) {
 
 } // namespace
 
-SPIRVEmitter::SPIRVEmitter(CompilerInstance &ci,
-                           const EmitSPIRVOptions &options)
+SPIRVEmitter::SPIRVEmitter(CompilerInstance &ci, EmitSPIRVOptions &options)
     : theCompilerInstance(ci), astContext(ci.getASTContext()),
       diags(ci.getDiagnostics()), spirvOptions(options),
       entryFunctionName(ci.getCodeGenOpts().HLSLEntryFunction),
@@ -523,7 +522,7 @@ SPIRVEmitter::SPIRVEmitter(CompilerInstance &ci,
       theBuilder(&theContext, &featureManager, options.enableReflect),
       typeTranslator(astContext, theBuilder, diags, options),
       declIdMapper(shaderModel, astContext, theBuilder, typeTranslator,
-                   featureManager, spirvOptions),
+                   featureManager, options),
       entryFunctionId(0), curFunction(nullptr), curThis(0),
       seenPushConstantAt(), isSpecConstantMode(false),
       needsLegalization(false) {
@@ -533,6 +532,12 @@ SPIRVEmitter::SPIRVEmitter(CompilerInstance &ci,
   if (options.invertY && !shaderModel.IsVS() && !shaderModel.IsDS() &&
       !shaderModel.IsGS())
     emitError("-fvk-invert-y can only be used in VS/DS/GS", {});
+
+  if (options.useGlslLayout && options.useDxLayout)
+    emitError("cannot specify both -fvk-use-dx-layout and -fvk-use-glsl-layout",
+              {});
+
+  options.Initialize();
 }
 
 void SPIRVEmitter::HandleTranslationUnit(ASTContext &context) {
@@ -909,7 +914,7 @@ bool SPIRVEmitter::loadIfAliasVarRef(const Expr *varExpr, SpirvEvalInfo &info) {
       info.setResultId(theBuilder.createLoad(ptrType, info));
 
     info.setStorageClass(spv::StorageClass::Uniform)
-        .setLayoutRule(LayoutRule::GLSLStd430)
+        .setLayoutRule(spirvOptions.sBufferLayoutRule)
         // Now it is a pointer to the global resource, which is lvalue.
         .setRValue(false)
         // Set to false to indicate that we've performed dereference over the
@@ -2614,7 +2619,7 @@ uint32_t SPIRVEmitter::processByteAddressBufferStructuredBufferGetDimensions(
     // size of the struct) must also be written to the second argument.
     uint32_t size = 0, stride = 0;
     std::tie(std::ignore, size) = typeTranslator.getAlignmentAndSize(
-        type, LayoutRule::GLSLStd430, &stride);
+        type, spirvOptions.sBufferLayoutRule, &stride);
     const auto sizeId = theBuilder.getConstantUint32(size);
     theBuilder.createStore(doExpr(expr->getArg(1)), sizeId);
   }

+ 2 - 2
tools/clang/lib/SPIRV/SPIRVEmitter.h

@@ -46,7 +46,7 @@ namespace spirv {
 /// through the AST is done manually instead of using ASTConsumer's harness.
 class SPIRVEmitter : public ASTConsumer {
 public:
-  SPIRVEmitter(CompilerInstance &ci, const EmitSPIRVOptions &options);
+  SPIRVEmitter(CompilerInstance &ci, EmitSPIRVOptions &options);
 
   void HandleTranslationUnit(ASTContext &context) override;
 
@@ -904,7 +904,7 @@ private:
   ASTContext &astContext;
   DiagnosticsEngine &diags;
 
-  EmitSPIRVOptions spirvOptions;
+  const EmitSPIRVOptions &spirvOptions;
 
   /// Entry function name and shader stage. Both of them are derived from the
   /// command line and should be const.

+ 0 - 7
tools/clang/lib/SPIRV/SpirvEvalInfo.h

@@ -19,13 +19,6 @@
 namespace clang {
 namespace spirv {
 
-/// Memory layout rules
-enum class LayoutRule {
-  Void,
-  GLSLStd140,
-  GLSLStd430,
-};
-
 /// Struct contains SPIR-V information from evaluating a Clang AST node.
 ///
 /// We need to report more information than just the <result-id> for SPIR-V:

+ 110 - 49
tools/clang/lib/SPIRV/TypeTranslator.cpp

@@ -28,9 +28,9 @@ constexpr uint32_t kStd140Vec4Alignment = 16u;
 inline bool isPow2(int val) { return (val & (val - 1)) == 0; }
 
 /// Rounds the given value up to the given power of 2.
-inline void roundToPow2(uint32_t *val, uint32_t pow2) {
+inline uint32_t roundToPow2(uint32_t val, uint32_t pow2) {
   assert(pow2 != 0);
-  *val = (*val + pow2 - 1) & ~(pow2 - 1);
+  return (val + pow2 - 1) & ~(pow2 - 1);
 }
 
 /// Returns true if the given vector type (of the given size) crosses the
@@ -159,7 +159,7 @@ bool TypeTranslator::isOpaqueStructType(QualType type) {
 }
 
 bool TypeTranslator::isOpaqueArrayType(QualType type) {
-  if (const auto* arrayType = type->getAsArrayTypeUnsafe())
+  if (const auto *arrayType = type->getAsArrayTypeUnsafe())
     return isOpaqueType(arrayType->getElementType());
   return false;
 }
@@ -1196,8 +1196,13 @@ TypeTranslator::getLayoutDecorations(const DeclContext *decl, LayoutRule rule) {
     // The next avaiable location after layouting the previos members
     const uint32_t nextLoc = offset;
 
-    alignUsingHLSLRelaxedLayout(fieldType, memberSize, &memberAlignment,
-                                &offset);
+    if (rule == LayoutRule::RelaxedGLSLStd140 ||
+        rule == LayoutRule::RelaxedGLSLStd430 ||
+        rule == LayoutRule::FxcCTBuffer)
+      alignUsingHLSLRelaxedLayout(fieldType, memberSize, &memberAlignment,
+                                  &offset);
+    else
+      offset = roundToPow2(offset, memberAlignment);
 
     // The vk::offset attribute takes precedence over all.
     if (const auto *offsetAttr = field->getAttr<VKOffsetAttr>()) {
@@ -1326,7 +1331,7 @@ uint32_t TypeTranslator::translateResourceType(QualType type, LayoutRule rule,
     bool asAlias = false;
     if (rule == LayoutRule::Void) {
       asAlias = true;
-      rule = LayoutRule::GLSLStd430;
+      rule = spirvOptions.sBufferLayoutRule;
     }
 
     auto &context = *theBuilder.getSPIRVContext();
@@ -1468,30 +1473,28 @@ 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, nullptr);
-      if (scalarAlignment <= 4)
-        *fieldAlignment = scalarAlignment;
-    }
+  QualType vecElemType = {};
+  const bool fieldIsVecType = isVectorType(fieldType, &vecElemType);
+
+  // 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.
+  if (fieldIsVecType) {
+    uint32_t scalarAlignment = 0;
+    std::tie(scalarAlignment, std::ignore) =
+        getAlignmentAndSize(vecElemType, LayoutRule::Void, nullptr);
+    if (scalarAlignment <= 4)
+      *fieldAlignment = scalarAlignment;
   }
 
-  roundToPow2(currentOffset, *fieldAlignment);
+  *currentOffset = 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 &&
+  if (fieldIsVecType &&
       improperStraddle(fieldType, fieldSize, *currentOffset)) {
     *fieldAlignment = kStd140Vec4Alignment;
-    roundToPow2(currentOffset, *fieldAlignment);
+    *currentOffset = roundToPow2(*currentOffset, *fieldAlignment);
   }
 }
 
@@ -1545,6 +1548,30 @@ TypeTranslator::getAlignmentAndSize(QualType type, LayoutRule rule,
   //
   // 10. If the member is an array of S structures, the S elements of the array
   //     are laid out in order, according to rule (9).
+  //
+  // This method supports multiple layout rules, all of them modifying the
+  // std140 rules listed above:
+  //
+  // std430:
+  // - Array base alignment and stride does not need to be rounded up to a
+  //   multiple of 16.
+  // - Struct base alignment does not need to be rounded up to a multiple of 16.
+  //
+  // Relaxed std140/std430:
+  // - Vector base alignment is set as its element type's base alignment.
+  //
+  // FxcCTBuffer:
+  // - Vector base alignment is set as its element type's base alignment.
+  // - Arrays/structs do not need to have padding at the end; arrays/structs do
+  //   not affect the base offset of the member following them.
+  // - Struct base alignment does not need to be rounded up to a multiple of 16.
+  //
+  // FxcSBuffer:
+  // - Vector/matrix/array base alignment is set as its element type's base
+  //   alignment.
+  // - Arrays/structs do not need to have padding at the end; arrays/structs do
+  //   not affect the base offset of the member following them.
+  // - Struct base alignment does not need to be rounded up to a multiple of 16.
 
   const auto desugaredType = desugarType(type);
   if (desugaredType != type) {
@@ -1559,8 +1586,6 @@ TypeTranslator::getAlignmentAndSize(QualType type, LayoutRule rule,
     if (isScalarType(type, &ty))
       if (const auto *builtinType = ty->getAs<BuiltinType>())
         switch (builtinType->getKind()) {
-        case BuiltinType::Void:
-          return {0, 0};
         case BuiltinType::Bool:
         case BuiltinType::Int:
         case BuiltinType::UInt:
@@ -1581,10 +1606,13 @@ TypeTranslator::getAlignmentAndSize(QualType type, LayoutRule rule,
     QualType elemType = {};
     uint32_t elemCount = {};
     if (isVectorType(type, &elemType, &elemCount)) {
-      uint32_t size = 0;
-      std::tie(std::ignore, size) = getAlignmentAndSize(elemType, rule, stride);
+      uint32_t alignment = 0, size = 0;
+      std::tie(alignment, size) = getAlignmentAndSize(elemType, rule, stride);
+      // Use element alignment for fxc rules
+      if (rule != LayoutRule::FxcCTBuffer && rule != LayoutRule::FxcSBuffer)
+        alignment = (elemCount == 3 ? 4 : elemCount) * size;
 
-      return {(elemCount == 3 ? 4 : elemCount) * size, elemCount * size};
+      return {alignment, elemCount * size};
     }
   }
 
@@ -1593,8 +1621,7 @@ TypeTranslator::getAlignmentAndSize(QualType type, LayoutRule rule,
     uint32_t rowCount = 0, colCount = 0;
     if (isMxNMatrix(type, &elemType, &rowCount, &colCount)) {
       uint32_t alignment = 0, size = 0;
-      std::tie(alignment, std::ignore) =
-          getAlignmentAndSize(elemType, rule, stride);
+      std::tie(alignment, size) = getAlignmentAndSize(elemType, rule, stride);
 
       // Matrices are treated as arrays of vectors:
       // The base alignment and array stride are set to match the base alignment
@@ -1603,9 +1630,18 @@ TypeTranslator::getAlignmentAndSize(QualType type, LayoutRule rule,
       bool isRowMajor = isRowMajorMatrix(type);
 
       const uint32_t vecStorageSize = isRowMajor ? colCount : rowCount;
+
+      if (rule == LayoutRule::FxcSBuffer) {
+        *stride = vecStorageSize * size;
+        // Use element alignment for fxc structured buffers
+        return {alignment, rowCount * colCount * size};
+      }
+
       alignment *= (vecStorageSize == 3 ? 4 : vecStorageSize);
-      if (rule == LayoutRule::GLSLStd140) {
-        roundToPow2(&alignment, kStd140Vec4Alignment);
+      if (rule == LayoutRule::GLSLStd140 ||
+          rule == LayoutRule::RelaxedGLSLStd140 ||
+          rule == LayoutRule::FxcCTBuffer) {
+        alignment = roundToPow2(alignment, kStd140Vec4Alignment);
       }
       *stride = alignment;
       size = (isRowMajor ? rowCount : colCount) * alignment;
@@ -1629,8 +1665,13 @@ TypeTranslator::getAlignmentAndSize(QualType type, LayoutRule rule,
       std::tie(memberAlignment, memberSize) =
           getAlignmentAndSize(field->getType(), rule, stride);
 
-      alignUsingHLSLRelaxedLayout(field->getType(), memberSize,
-                                  &memberAlignment, &structSize);
+      if (rule == LayoutRule::RelaxedGLSLStd140 ||
+          rule == LayoutRule::RelaxedGLSLStd430 ||
+          rule == LayoutRule::FxcCTBuffer)
+        alignUsingHLSLRelaxedLayout(field->getType(), memberSize,
+                                    &memberAlignment, &structSize);
+      else
+        structSize = roundToPow2(structSize, memberAlignment);
 
       // The base alignment of the structure is N, where N is the largest
       // base alignment value of any of its members...
@@ -1638,36 +1679,56 @@ TypeTranslator::getAlignmentAndSize(QualType type, LayoutRule rule,
       structSize += memberSize;
     }
 
-    if (rule == LayoutRule::GLSLStd140) {
+    if (rule == LayoutRule::GLSLStd140 ||
+        rule == LayoutRule::RelaxedGLSLStd140) {
       // ... and rounded up to the base alignment of a vec4.
-      roundToPow2(&maxAlignment, kStd140Vec4Alignment);
+      maxAlignment = roundToPow2(maxAlignment, kStd140Vec4Alignment);
+    }
+
+    if (rule != LayoutRule::FxcCTBuffer && rule != LayoutRule::FxcSBuffer) {
+      // The base offset of the member following the sub-structure is rounded up
+      // to the next multiple of the base alignment of the structure.
+      structSize = roundToPow2(structSize, maxAlignment);
     }
-    // The base offset of the member following the sub-structure is rounded up
-    // to the next multiple of the base alignment of the structure.
-    roundToPow2(&structSize, maxAlignment);
     return {maxAlignment, structSize};
   }
 
   // Rule 4, 6, 8, and 10
   if (const auto *arrayType = astContext.getAsConstantArrayType(type)) {
+    const auto elemCount = arrayType->getSize().getZExtValue();
     uint32_t alignment = 0, size = 0;
     std::tie(alignment, size) =
         getAlignmentAndSize(arrayType->getElementType(), rule, stride);
 
-    if (rule == LayoutRule::GLSLStd140) {
+    if (rule == LayoutRule::FxcSBuffer) {
+      *stride = size;
+      // Use element alignment for fxc structured buffers
+      return {alignment, size * elemCount};
+    }
+
+    if (rule == LayoutRule::GLSLStd140 ||
+        rule == LayoutRule::RelaxedGLSLStd140 ||
+        rule == LayoutRule::FxcCTBuffer) {
       // The base alignment and array stride are set to match the base alignment
       // of a single array element, according to rules 1, 2, and 3, and rounded
       // up to the base alignment of a vec4.
-      roundToPow2(&alignment, kStd140Vec4Alignment);
+      alignment = roundToPow2(alignment, kStd140Vec4Alignment);
+    }
+    if (rule == LayoutRule::FxcCTBuffer) {
+      // In fxc cbuffer/tbuffer packing rules, arrays does not affect the data
+      // packing after it. But we still need to make sure paddings are inserted
+      // internally if necessary.
+      *stride = roundToPow2(size, alignment);
+      size += *stride * (elemCount - 1);
+    } else {
+      // Need to round size up considering stride for scalar types
+      size = roundToPow2(size, alignment);
+      *stride = size; // Use size instead of alignment here for Rule 10
+      size *= elemCount;
+      // The base offset of the member following the array is rounded up to the
+      // next multiple of the base alignment.
+      size = roundToPow2(size, alignment);
     }
-    // Need to round size up considering stride for scalar types
-    roundToPow2(&size, alignment);
-    *stride = size; // Use size instead of alignment here for Rule 10
-    // TODO: handle extra large array size?
-    size *= static_cast<uint32_t>(arrayType->getSize().getZExtValue());
-    // The base offset of the member following the array is rounded up to the
-    // next multiple of the base alignment.
-    roundToPow2(&size, alignment);
 
     return {alignment, size};
   }

+ 351 - 0
tools/clang/test/CodeGenSPIRV/vk.layout.cbuffer.fxc.hlsl

@@ -0,0 +1,351 @@
+// Run: %dxc -T ps_6_0 -E main -fvk-use-dx-layout
+
+// fxc layout:
+//
+//   struct S
+//   {
+//
+//       float scalar1;                 // Offset:    0
+//       double scalar2;                // Offset:    8
+//       float3 vector1;                // Offset:   16
+//       float3 vector2;                // Offset:   32
+//       double3 vector3;               // Offset:   48
+//       double3 vector4;               // Offset:   80
+//       float2x3 matrix1;              // Offset:  112
+//       row_major float2x3 matrix2;    // Offset:  160
+//       float3x2 matrix3;              // Offset:  192
+//       row_major float3x2 matrix4;    // Offset:  224
+//       float scalarArray1;            // Offset:  272
+//       double scalarArray2[2];        // Offset:  288
+//       float3 vectorArray1;           // Offset:  320
+//       float3 vectorArray2[2];        // Offset:  336
+//       double3 vectorArray3[3];       // Offset:  368
+//       double3 vectorArray4[4];       // Offset:  464
+//       float2x3 matrixArray1;         // Offset:  592
+//       row_major float2x3 matrixArray2[2];// Offset:  640
+//       float3x2 matrixArray3[3];      // Offset:  704
+//       row_major float3x2 matrixArray4[4];// Offset:  800
+//
+//   }                                  // Size:   984
+
+// CHECK: OpDecorate %_arr_float_uint_1 ArrayStride 16
+// CHECK: OpDecorate %_arr_double_uint_2 ArrayStride 16
+// CHECK: OpDecorate %_arr_v3float_uint_1 ArrayStride 16
+// CHECK: OpDecorate %_arr_v3float_uint_2 ArrayStride 16
+// CHECK: OpDecorate %_arr_v3double_uint_3 ArrayStride 32
+// CHECK: OpDecorate %_arr_v3double_uint_4 ArrayStride 32
+// CHECK: OpDecorate %_arr_mat2v3float_uint_1 ArrayStride 48
+// CHECK: OpDecorate %_arr_mat2v3float_uint_2 ArrayStride 32
+// CHECK: OpDecorate %_arr_mat3v2float_uint_3 ArrayStride 32
+// CHECK: OpDecorate %_arr_mat3v2float_uint_4 ArrayStride 48
+
+// CHECK: OpMemberDecorate %S 0 Offset 0
+// CHECK: OpMemberDecorate %S 1 Offset 8
+// CHECK: OpMemberDecorate %S 2 Offset 16
+// CHECK: OpMemberDecorate %S 3 Offset 32
+// CHECK: OpMemberDecorate %S 4 Offset 48
+// CHECK: OpMemberDecorate %S 5 Offset 80
+// CHECK: OpMemberDecorate %S 6 Offset 112
+// CHECK: OpMemberDecorate %S 6 MatrixStride 16
+// CHECK: OpMemberDecorate %S 6 RowMajor
+// CHECK: OpMemberDecorate %S 7 Offset 160
+// CHECK: OpMemberDecorate %S 7 MatrixStride 16
+// CHECK: OpMemberDecorate %S 7 ColMajor
+// CHECK: OpMemberDecorate %S 8 Offset 192
+// CHECK: OpMemberDecorate %S 8 MatrixStride 16
+// CHECK: OpMemberDecorate %S 8 RowMajor
+// CHECK: OpMemberDecorate %S 9 Offset 224
+// CHECK: OpMemberDecorate %S 9 MatrixStride 16
+// CHECK: OpMemberDecorate %S 9 ColMajor
+// CHECK: OpMemberDecorate %S 10 Offset 272
+// CHECK: OpMemberDecorate %S 11 Offset 288
+// CHECK: OpMemberDecorate %S 12 Offset 320
+// CHECK: OpMemberDecorate %S 13 Offset 336
+// CHECK: OpMemberDecorate %S 14 Offset 368
+// CHECK: OpMemberDecorate %S 15 Offset 464
+// CHECK: OpMemberDecorate %S 16 Offset 592
+// CHECK: OpMemberDecorate %S 16 MatrixStride 16
+// CHECK: OpMemberDecorate %S 16 RowMajor
+// CHECK: OpMemberDecorate %S 17 Offset 640
+// CHECK: OpMemberDecorate %S 17 MatrixStride 16
+// CHECK: OpMemberDecorate %S 17 ColMajor
+// CHECK: OpMemberDecorate %S 18 Offset 704
+// CHECK: OpMemberDecorate %S 18 MatrixStride 16
+// CHECK: OpMemberDecorate %S 18 RowMajor
+// CHECK: OpMemberDecorate %S 19 Offset 800
+// CHECK: OpMemberDecorate %S 19 MatrixStride 16
+// CHECK: OpMemberDecorate %S 19 ColMajor
+// CHECK: OpDecorate %_arr_S_uint_2 ArrayStride 992
+
+struct S {
+    float              scalar1;
+    double             scalar2;
+    float3             vector1;
+    float3             vector2;
+    double3            vector3;
+    double3            vector4;
+    float2x3           matrix1;
+    row_major float2x3 matrix2;
+    float3x2           matrix3;
+    row_major float3x2 matrix4;
+    float              scalarArray1[1];
+    double             scalarArray2[2];
+    float3             vectorArray1[1];
+    float3             vectorArray2[2];
+    double3            vectorArray3[3];
+    double3            vectorArray4[4];
+    float2x3           matrixArray1[1];
+    row_major float2x3 matrixArray2[2];
+    float3x2           matrixArray3[3];
+    row_major float3x2 matrixArray4[4];
+};
+
+// fxc layout:
+//
+// cbuffer MyCBuffer
+// {
+//
+//   float CB_scalar1;                  // Offset:    0 Size:     4
+//
+//   struct S
+//   {
+//
+//       float scalar1;                 // Offset:   16
+//       double scalar2;                // Offset:   24
+//       float3 vector1;                // Offset:   32
+//       float3 vector2;                // Offset:   48
+//       double3 vector3;               // Offset:   64
+//       double3 vector4;               // Offset:   96
+//       float2x3 matrix1;              // Offset:  128
+//       row_major float2x3 matrix2;    // Offset:  176
+//       float3x2 matrix3;              // Offset:  208
+//       row_major float3x2 matrix4;    // Offset:  240
+//       float scalarArray1;            // Offset:  288
+//       double scalarArray2[2];        // Offset:  304
+//       float3 vectorArray1;           // Offset:  336
+//       float3 vectorArray2[2];        // Offset:  352
+//       double3 vectorArray3[3];       // Offset:  384
+//       double3 vectorArray4[4];       // Offset:  480
+//       float2x3 matrixArray1;         // Offset:  608
+//       row_major float2x3 matrixArray2[2];// Offset:  656
+//       float3x2 matrixArray3[3];      // Offset:  720
+//       row_major float3x2 matrixArray4[4];// Offset:  816
+//
+//   } CB_sArray[2];                    // Offset:   16 Size:  1976 [unused]
+//   float CB_scalarArray1;             // Offset: 2000 Size:     4 [unused]
+//   float3 CB_vectorArray1;            // Offset: 2016 Size:    12 [unused]
+//   float3 CB_vector1;                 // Offset: 2032 Size:    12 [unused]
+//   float2x3 CB_matrixArray1;          // Offset: 2048 Size:    40 [unused]
+//   float3 CB_vector2;                 // Offset: 2096 Size:    12 [unused]
+//   double CB_scalarArray2[2];         // Offset: 2112 Size:    24 [unused]
+//   float2x3 CB_matrix1;               // Offset: 2144 Size:    40 [unused]
+//   double3 CB_vector3;                // Offset: 2192 Size:    24 [unused]
+//   row_major float2x3 CB_matrix2;     // Offset: 2224 Size:    28 [unused]
+//   row_major float2x3 CB_matrixArray2[2];// Offset: 2256 Size:    60 [unused]
+//   float3x2 CB_matrix3;               // Offset: 2320 Size:    28 [unused]
+//   row_major float3x2 CB_matrix4;     // Offset: 2352 Size:    40 [unused]
+//   float3 CB_vectorArray2[2];         // Offset: 2400 Size:    28 [unused]
+//   float3x2 CB_matrixArray3[3];       // Offset: 2432 Size:    92 [unused]
+//   double3 CB_vectorArray3[3];        // Offset: 2528 Size:    88 [unused]
+//   row_major float3x2 CB_matrixArray4[4];// Offset: 2624 Size:   184 [unused]
+//   double3 CB_vector4;                // Offset: 2816 Size:    24 [unused]
+//   double3 CB_vectorArray4[4];        // Offset: 2848 Size:   120 [unused]
+//   double CB_scalar2;                 // Offset: 2968 Size:     8 [unused]
+//   float3 CB_vector5;                 // Offset: 2976 Size:    12 [unused]
+//   int CB_scalarArray3[3];            // Offset: 2992 Size:    36 [unused]
+//   float3 CB_vector6;                 // Offset: 3028 Size:    12 [unused]
+//
+// }
+
+// CHECK: OpMemberDecorate %type_MyCBuffer 0 Offset 0
+// CHECK: OpMemberDecorate %type_MyCBuffer 1 Offset 16
+// CHECK: OpMemberDecorate %type_MyCBuffer 2 Offset 2000
+// CHECK: OpMemberDecorate %type_MyCBuffer 3 Offset 2016
+// CHECK: OpMemberDecorate %type_MyCBuffer 4 Offset 2032
+// CHECK: OpMemberDecorate %type_MyCBuffer 5 Offset 2048
+// CHECK: OpMemberDecorate %type_MyCBuffer 5 MatrixStride 16
+// CHECK: OpMemberDecorate %type_MyCBuffer 5 RowMajor
+// CHECK: OpMemberDecorate %type_MyCBuffer 6 Offset 2096
+// CHECK: OpMemberDecorate %type_MyCBuffer 7 Offset 2112
+// CHECK: OpMemberDecorate %type_MyCBuffer 8 Offset 2144
+// CHECK: OpMemberDecorate %type_MyCBuffer 8 MatrixStride 16
+// CHECK: OpMemberDecorate %type_MyCBuffer 8 RowMajor
+// CHECK: OpMemberDecorate %type_MyCBuffer 9 Offset 2192
+// CHECK: OpMemberDecorate %type_MyCBuffer 10 Offset 2224
+// CHECK: OpMemberDecorate %type_MyCBuffer 10 MatrixStride 16
+// CHECK: OpMemberDecorate %type_MyCBuffer 10 ColMajor
+// CHECK: OpMemberDecorate %type_MyCBuffer 11 Offset 2256
+// CHECK: OpMemberDecorate %type_MyCBuffer 11 MatrixStride 16
+// CHECK: OpMemberDecorate %type_MyCBuffer 11 ColMajor
+// CHECK: OpMemberDecorate %type_MyCBuffer 12 Offset 2320
+// CHECK: OpMemberDecorate %type_MyCBuffer 12 MatrixStride 16
+// CHECK: OpMemberDecorate %type_MyCBuffer 12 RowMajor
+// CHECK: OpMemberDecorate %type_MyCBuffer 13 Offset 2352
+// CHECK: OpMemberDecorate %type_MyCBuffer 13 MatrixStride 16
+// CHECK: OpMemberDecorate %type_MyCBuffer 13 ColMajor
+// CHECK: OpMemberDecorate %type_MyCBuffer 14 Offset 2400
+// CHECK: OpMemberDecorate %type_MyCBuffer 15 Offset 2432
+// CHECK: OpMemberDecorate %type_MyCBuffer 15 MatrixStride 16
+// CHECK: OpMemberDecorate %type_MyCBuffer 15 RowMajor
+// CHECK: OpMemberDecorate %type_MyCBuffer 16 Offset 2528
+// CHECK: OpMemberDecorate %type_MyCBuffer 17 Offset 2624
+// CHECK: OpMemberDecorate %type_MyCBuffer 17 MatrixStride 16
+// CHECK: OpMemberDecorate %type_MyCBuffer 17 ColMajor
+// CHECK: OpMemberDecorate %type_MyCBuffer 18 Offset 2816
+// CHECK: OpMemberDecorate %type_MyCBuffer 19 Offset 2848
+// CHECK: OpMemberDecorate %type_MyCBuffer 20 Offset 2968
+// CHECK: OpMemberDecorate %type_MyCBuffer 21 Offset 2976
+// CHECK: OpMemberDecorate %type_MyCBuffer 22 Offset 2992
+// CHECK: OpMemberDecorate %type_MyCBuffer 23 Offset 3028
+
+cbuffer MyCBuffer
+{
+    float              CB_scalar1;
+    S                  CB_sArray[2];
+    float              CB_scalarArray1[1];
+    float3             CB_vectorArray1[1];
+    float3             CB_vector1;
+    float2x3           CB_matrixArray1[1];
+    float3             CB_vector2;
+    double             CB_scalarArray2[2];
+    float2x3           CB_matrix1;
+    double3            CB_vector3;
+    row_major float2x3 CB_matrix2;
+    row_major float2x3 CB_matrixArray2[2];
+    float3x2           CB_matrix3;
+    row_major float3x2 CB_matrix4;
+    float3             CB_vectorArray2[2];
+    float3x2           CB_matrixArray3[3];
+    double3            CB_vectorArray3[3];
+    row_major float3x2 CB_matrixArray4[4];
+    double3            CB_vector4;
+    double3            CB_vectorArray4[4];
+    double             CB_scalar2;
+    float3             CB_vector5;
+    int                CB_scalarArray3[3];
+    float3             CB_vector6;
+};
+
+// fxc layout:
+//
+// tbuffer MyTBuffer
+// {
+//
+//   float TB_scalar1;                  // Offset:    0 Size:     4
+//
+//   struct S
+//   {
+//
+//       float scalar1;                 // Offset:   16
+//       double scalar2;                // Offset:   24
+//       float3 vector1;                // Offset:   32
+//       float3 vector2;                // Offset:   48
+//       double3 vector3;               // Offset:   64
+//       double3 vector4;               // Offset:   96
+//       float2x3 matrix1;              // Offset:  128
+//       row_major float2x3 matrix2;    // Offset:  176
+//       float3x2 matrix3;              // Offset:  208
+//       row_major float3x2 matrix4;    // Offset:  240
+//       float scalarArray1;            // Offset:  288
+//       double scalarArray2[2];        // Offset:  304
+//       float3 vectorArray1;           // Offset:  336
+//       float3 vectorArray2[2];        // Offset:  352
+//       double3 vectorArray3[3];       // Offset:  384
+//       double3 vectorArray4[4];       // Offset:  480
+//       float2x3 matrixArray1;         // Offset:  608
+//       row_major float2x3 matrixArray2[2];// Offset:  656
+//       float3x2 matrixArray3[3];      // Offset:  720
+//       row_major float3x2 matrixArray4[4];// Offset:  816
+//
+//   } TB_sArray[2];                    // Offset:   16 Size:  1976 [unused]
+//   float TB_scalarArray1;             // Offset: 2000 Size:     4 [unused]
+//   float3 TB_vectorArray1;            // Offset: 2016 Size:    12 [unused]
+//   float3 TB_vector1;                 // Offset: 2032 Size:    12 [unused]
+//   float2x3 TB_matrixArray1;          // Offset: 2048 Size:    40 [unused]
+//   float3 TB_vector2;                 // Offset: 2096 Size:    12 [unused]
+//   double TB_scalarArray2[2];         // Offset: 2112 Size:    24 [unused]
+//   float2x3 TB_matrix1;               // Offset: 2144 Size:    40 [unused]
+//   double3 TB_vector3;                // Offset: 2192 Size:    24 [unused]
+//   row_major float2x3 TB_matrix2;     // Offset: 2224 Size:    28 [unused]
+//   row_major float2x3 TB_matrixArray2[2];// Offset: 2256 Size:    60 [unused]
+//   float3x2 TB_matrix3;               // Offset: 2320 Size:    28 [unused]
+//   row_major float3x2 TB_matrix4;     // Offset: 2352 Size:    40 [unused]
+//   float3 TB_vectorArray2[2];         // Offset: 2400 Size:    28 [unused]
+//   float3x2 TB_matrixArray3[3];       // Offset: 2432 Size:    92 [unused]
+//   double3 TB_vectorArray3[3];        // Offset: 2528 Size:    88 [unused]
+//   row_major float3x2 TB_matrixArray4[4];// Offset: 2624 Size:   184 [unused]
+//   double3 TB_vector4;                // Offset: 2816 Size:    24 [unused]
+//   double3 TB_vectorArray4[4];        // Offset: 2848 Size:   120 [unused]
+//   double TB_scalar2;                 // Offset: 2968 Size:     8 [unused]
+//
+// }
+
+// CHECK: OpMemberDecorate %type_MyTBuffer 0 Offset 0
+// CHECK: OpMemberDecorate %type_MyTBuffer 1 Offset 16
+// CHECK: OpMemberDecorate %type_MyTBuffer 2 Offset 2000
+// CHECK: OpMemberDecorate %type_MyTBuffer 3 Offset 2016
+// CHECK: OpMemberDecorate %type_MyTBuffer 4 Offset 2032
+// CHECK: OpMemberDecorate %type_MyTBuffer 5 Offset 2048
+// CHECK: OpMemberDecorate %type_MyTBuffer 5 MatrixStride 16
+// CHECK: OpMemberDecorate %type_MyTBuffer 5 RowMajor
+// CHECK: OpMemberDecorate %type_MyTBuffer 6 Offset 2096
+// CHECK: OpMemberDecorate %type_MyTBuffer 7 Offset 2112
+// CHECK: OpMemberDecorate %type_MyTBuffer 8 Offset 2144
+// CHECK: OpMemberDecorate %type_MyTBuffer 8 MatrixStride 16
+// CHECK: OpMemberDecorate %type_MyTBuffer 8 RowMajor
+// CHECK: OpMemberDecorate %type_MyTBuffer 9 Offset 2192
+// CHECK: OpMemberDecorate %type_MyTBuffer 10 Offset 2224
+// CHECK: OpMemberDecorate %type_MyTBuffer 10 MatrixStride 16
+// CHECK: OpMemberDecorate %type_MyTBuffer 10 ColMajor
+// CHECK: OpMemberDecorate %type_MyTBuffer 11 Offset 2256
+// CHECK: OpMemberDecorate %type_MyTBuffer 11 MatrixStride 16
+// CHECK: OpMemberDecorate %type_MyTBuffer 11 ColMajor
+// CHECK: OpMemberDecorate %type_MyTBuffer 12 Offset 2320
+// CHECK: OpMemberDecorate %type_MyTBuffer 12 MatrixStride 16
+// CHECK: OpMemberDecorate %type_MyTBuffer 12 RowMajor
+// CHECK: OpMemberDecorate %type_MyTBuffer 13 Offset 2352
+// CHECK: OpMemberDecorate %type_MyTBuffer 13 MatrixStride 16
+// CHECK: OpMemberDecorate %type_MyTBuffer 13 ColMajor
+// CHECK: OpMemberDecorate %type_MyTBuffer 14 Offset 2400
+// CHECK: OpMemberDecorate %type_MyTBuffer 15 Offset 2432
+// CHECK: OpMemberDecorate %type_MyTBuffer 15 MatrixStride 16
+// CHECK: OpMemberDecorate %type_MyTBuffer 15 RowMajor
+// CHECK: OpMemberDecorate %type_MyTBuffer 16 Offset 2528
+// CHECK: OpMemberDecorate %type_MyTBuffer 17 Offset 2624
+// CHECK: OpMemberDecorate %type_MyTBuffer 17 MatrixStride 16
+// CHECK: OpMemberDecorate %type_MyTBuffer 17 ColMajor
+// CHECK: OpMemberDecorate %type_MyTBuffer 18 Offset 2816
+// CHECK: OpMemberDecorate %type_MyTBuffer 19 Offset 2848
+// CHECK: OpMemberDecorate %type_MyTBuffer 20 Offset 2968
+
+tbuffer MyTBuffer
+{
+    float              TB_scalar1;
+    S                  TB_sArray[2];
+    float              TB_scalarArray1[1];
+    float3             TB_vectorArray1[1];
+    float3             TB_vector1;
+    float2x3           TB_matrixArray1[1];
+    float3             TB_vector2;
+    double             TB_scalarArray2[2];
+    float2x3           TB_matrix1;
+    double3            TB_vector3;
+    row_major float2x3 TB_matrix2;
+    row_major float2x3 TB_matrixArray2[2];
+    float3x2           TB_matrix3;
+    row_major float3x2 TB_matrix4;
+    float3             TB_vectorArray2[2];
+    float3x2           TB_matrixArray3[3];
+    double3            TB_vectorArray3[3];
+    row_major float3x2 TB_matrixArray4[4];
+    double3            TB_vector4;
+    double3            TB_vectorArray4[4];
+    double             TB_scalar2;
+};
+
+ConstantBuffer<S> MyConstantBuffer;
+TextureBuffer<S> MyTextureBuffer;
+
+float4 main() : SV_Target {
+    return CB_scalar1 + TB_scalar1 + MyConstantBuffer.scalar1 + MyTextureBuffer.scalar1;
+}

+ 229 - 0
tools/clang/test/CodeGenSPIRV/vk.layout.sbuffer.fxc.hlsl

@@ -0,0 +1,229 @@
+// Run: %dxc -T ps_6_0 -E main -fvk-use-dx-layout
+
+// fxc layout:
+//
+//   struct S
+//   {
+//
+//       float scalar1;                 // Offset:    0
+//       double scalar2;                // Offset:    8
+//       float3 vector1;                // Offset:   16
+//       float3 vector2;                // Offset:   28
+//       double3 vector3;               // Offset:   40
+//       double3 vector4;               // Offset:   64
+//       float2x3 matrix1;              // Offset:   88
+//       row_major float2x3 matrix2;    // Offset:  112
+//       float3x2 matrix3;              // Offset:  136
+//       row_major float3x2 matrix4;    // Offset:  160
+//       float scalarArray1;            // Offset:  184
+//       double scalarArray2[2];        // Offset:  192
+//       float3 vectorArray1;           // Offset:  208
+//       float3 vectorArray2[2];        // Offset:  220
+//       double3 vectorArray3[3];       // Offset:  248
+//       double3 vectorArray4[4];       // Offset:  320
+//       float2x3 matrixArray1;         // Offset:  416
+//       row_major float2x3 matrixArray2[2];// Offset:  440
+//       float3x2 matrixArray3[3];      // Offset:  488
+//       row_major float3x2 matrixArray4[4];// Offset:  560
+//
+//   }                                  // Size:   656
+
+// CHECK: OpDecorate %_arr_float_uint_1 ArrayStride 4
+// CHECK: OpDecorate %_arr_double_uint_2 ArrayStride 8
+// CHECK: OpDecorate %_arr_v3float_uint_1 ArrayStride 12
+// CHECK: OpDecorate %_arr_v3float_uint_2 ArrayStride 12
+// CHECK: OpDecorate %_arr_v3double_uint_3 ArrayStride 24
+// CHECK: OpDecorate %_arr_v3double_uint_4 ArrayStride 24
+// CHECK: OpDecorate %_arr_mat2v3float_uint_1 ArrayStride 24
+// CHECK: OpDecorate %_arr_mat2v3float_uint_2 ArrayStride 24
+// CHECK: OpDecorate %_arr_mat3v2float_uint_3 ArrayStride 24
+// CHECK: OpDecorate %_arr_mat3v2float_uint_4 ArrayStride 24
+
+// CHECK: OpMemberDecorate %S 0 Offset 0
+// CHECK: OpMemberDecorate %S 1 Offset 8
+// CHECK: OpMemberDecorate %S 2 Offset 16
+// CHECK: OpMemberDecorate %S 3 Offset 28
+// CHECK: OpMemberDecorate %S 4 Offset 40
+// CHECK: OpMemberDecorate %S 5 Offset 64
+// CHECK: OpMemberDecorate %S 6 Offset 88
+// CHECK: OpMemberDecorate %S 6 MatrixStride 8
+// CHECK: OpMemberDecorate %S 6 RowMajor
+// CHECK: OpMemberDecorate %S 7 Offset 112
+// CHECK: OpMemberDecorate %S 7 MatrixStride 12
+// CHECK: OpMemberDecorate %S 7 ColMajor
+// CHECK: OpMemberDecorate %S 8 Offset 136
+// CHECK: OpMemberDecorate %S 8 MatrixStride 12
+// CHECK: OpMemberDecorate %S 8 RowMajor
+// CHECK: OpMemberDecorate %S 9 Offset 160
+// CHECK: OpMemberDecorate %S 9 MatrixStride 8
+// CHECK: OpMemberDecorate %S 9 ColMajor
+// CHECK: OpMemberDecorate %S 10 Offset 184
+// CHECK: OpMemberDecorate %S 11 Offset 192
+// CHECK: OpMemberDecorate %S 12 Offset 208
+// CHECK: OpMemberDecorate %S 13 Offset 220
+// CHECK: OpMemberDecorate %S 14 Offset 248
+// CHECK: OpMemberDecorate %S 15 Offset 320
+// CHECK: OpMemberDecorate %S 16 Offset 416
+// CHECK: OpMemberDecorate %S 16 MatrixStride 8
+// CHECK: OpMemberDecorate %S 16 RowMajor
+// CHECK: OpMemberDecorate %S 17 Offset 440
+// CHECK: OpMemberDecorate %S 17 MatrixStride 12
+// CHECK: OpMemberDecorate %S 17 ColMajor
+// CHECK: OpMemberDecorate %S 18 Offset 488
+// CHECK: OpMemberDecorate %S 18 MatrixStride 12
+// CHECK: OpMemberDecorate %S 18 RowMajor
+// CHECK: OpMemberDecorate %S 19 Offset 560
+// CHECK: OpMemberDecorate %S 19 MatrixStride 8
+// CHECK: OpMemberDecorate %S 19 ColMajor
+// CHECK: OpDecorate %_runtimearr_S ArrayStride 656
+
+// fxc layout:
+//
+//   struct T
+//   {
+//
+//       float scalar1;                 // Offset:    0
+//
+//       struct S
+//       {
+//
+//           float scalar1;             // Offset:    8
+//           double scalar2;            // Offset:   16
+//           float3 vector1;            // Offset:   24
+//           float3 vector2;            // Offset:   36
+//           double3 vector3;           // Offset:   48
+//           double3 vector4;           // Offset:   72
+//           float2x3 matrix1;          // Offset:   96
+//           row_major float2x3 matrix2;// Offset:  120
+//           float3x2 matrix3;          // Offset:  144
+//           row_major float3x2 matrix4;// Offset:  168
+//           float scalarArray1;        // Offset:  192
+//           double scalarArray2[2];    // Offset:  200
+//           float3 vectorArray1;       // Offset:  216
+//           float3 vectorArray2[2];    // Offset:  228
+//           double3 vectorArray3[3];   // Offset:  256
+//           double3 vectorArray4[4];   // Offset:  328
+//           float2x3 matrixArray1;     // Offset:  424
+//           row_major float2x3 matrixArray2[2];// Offset:  448
+//           float3x2 matrixArray3[3];  // Offset:  496
+//           row_major float3x2 matrixArray4[4];// Offset:  568
+//
+//       } sArray[2];                   // Offset:    8
+//       float scalarArray1;            // Offset: 1320
+//       float3 vectorArray1;           // Offset: 1324
+//       float3 vector1;                // Offset: 1336
+//       float2x3 matrixArray1;         // Offset: 1348
+//       float3 vector2;                // Offset: 1372
+//       double scalarArray2[2];        // Offset: 1384
+//       float2x3 matrix1;              // Offset: 1400
+//       double3 vector3;               // Offset: 1424
+//       row_major float2x3 matrix2;    // Offset: 1448
+//       row_major float2x3 matrixArray2[2];// Offset: 1472
+//       float3x2 matrix3;              // Offset: 1520
+//       row_major float3x2 matrix4;    // Offset: 1544
+//       float3 vectorArray2[2];        // Offset: 1568
+//       float3x2 matrixArray3[3];      // Offset: 1592
+//       double3 vectorArray3[3];       // Offset: 1664
+//       row_major float3x2 matrixArray4[4];// Offset: 1736
+//       double3 vector4;               // Offset: 1832
+//       double3 vectorArray4[4];       // Offset: 1856
+//       double scalar2;                // Offset: 1952
+//
+//   }                                  // Size:  1960
+
+// CHECK: OpDecorate %_arr_S_uint_2 ArrayStride 656
+
+// CHECK: OpMemberDecorate %T 0 Offset 0
+// CHECK: OpMemberDecorate %T 1 Offset 8
+// CHECK: OpMemberDecorate %T 2 Offset 1320
+// CHECK: OpMemberDecorate %T 3 Offset 1324
+// CHECK: OpMemberDecorate %T 4 Offset 1336
+// CHECK: OpMemberDecorate %T 5 Offset 1348
+// CHECK: OpMemberDecorate %T 5 MatrixStride 8
+// CHECK: OpMemberDecorate %T 5 RowMajor
+// CHECK: OpMemberDecorate %T 6 Offset 1372
+// CHECK: OpMemberDecorate %T 7 Offset 1384
+// CHECK: OpMemberDecorate %T 8 Offset 1400
+// CHECK: OpMemberDecorate %T 8 MatrixStride 8
+// CHECK: OpMemberDecorate %T 8 RowMajor
+// CHECK: OpMemberDecorate %T 9 Offset 1424
+// CHECK: OpMemberDecorate %T 10 Offset 1448
+// CHECK: OpMemberDecorate %T 10 MatrixStride 12
+// CHECK: OpMemberDecorate %T 10 ColMajor
+// CHECK: OpMemberDecorate %T 11 Offset 1472
+// CHECK: OpMemberDecorate %T 11 MatrixStride 12
+// CHECK: OpMemberDecorate %T 11 ColMajor
+// CHECK: OpMemberDecorate %T 12 Offset 1520
+// CHECK: OpMemberDecorate %T 12 MatrixStride 12
+// CHECK: OpMemberDecorate %T 12 RowMajor
+// CHECK: OpMemberDecorate %T 13 Offset 1544
+// CHECK: OpMemberDecorate %T 13 MatrixStride 8
+// CHECK: OpMemberDecorate %T 13 ColMajor
+// CHECK: OpMemberDecorate %T 14 Offset 1568
+// CHECK: OpMemberDecorate %T 15 Offset 1592
+// CHECK: OpMemberDecorate %T 15 MatrixStride 12
+// CHECK: OpMemberDecorate %T 15 RowMajor
+// CHECK: OpMemberDecorate %T 16 Offset 1664
+// CHECK: OpMemberDecorate %T 17 Offset 1736
+// CHECK: OpMemberDecorate %T 17 MatrixStride 8
+// CHECK: OpMemberDecorate %T 17 ColMajor
+// CHECK: OpMemberDecorate %T 18 Offset 1832
+// CHECK: OpMemberDecorate %T 19 Offset 1856
+// CHECK: OpMemberDecorate %T 20 Offset 1952
+
+// CHECK: OpDecorate %_runtimearr_T ArrayStride 1960
+
+struct S {
+    float              scalar1;
+    double             scalar2;
+    float3             vector1;
+    float3             vector2;
+    double3            vector3;
+    double3            vector4;
+    float2x3           matrix1;
+    row_major float2x3 matrix2;
+    float3x2           matrix3;
+    row_major float3x2 matrix4;
+    float              scalarArray1[1];
+    double             scalarArray2[2];
+    float3             vectorArray1[1];
+    float3             vectorArray2[2];
+    double3            vectorArray3[3];
+    double3            vectorArray4[4];
+    float2x3           matrixArray1[1];
+    row_major float2x3 matrixArray2[2];
+    float3x2           matrixArray3[3];
+    row_major float3x2 matrixArray4[4];
+};
+
+struct T {
+    float              scalar1;
+    S                  sArray[2];
+    float              scalarArray1[1];
+    float3             vectorArray1[1];
+    float3             vector1;
+    float2x3           matrixArray1[1];
+    float3             vector2;
+    double             scalarArray2[2];
+    float2x3           matrix1;
+    double3            vector3;
+    row_major float2x3 matrix2;
+    row_major float2x3 matrixArray2[2];
+    float3x2           matrix3;
+    row_major float3x2 matrix4;
+    float3             vectorArray2[2];
+    float3x2           matrixArray3[3];
+    double3            vectorArray3[3];
+    row_major float3x2 matrixArray4[4];
+    double3            vector4;
+    double3            vectorArray4[4];
+    double             scalar2;
+};
+
+
+StructuredBuffer<S> MySBuffer1;
+StructuredBuffer<T> MySBuffer2;
+
+float4 main() : SV_Target {
+    return MySBuffer1[0].scalar1 + MySBuffer2[0].scalar1;
+}

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

@@ -470,6 +470,7 @@ public:
           spirvOpts.disableValidation = opts.DisableValidation;
           spirvOpts.invertY = opts.VkInvertY;
           spirvOpts.useGlslLayout = opts.VkUseGlslLayout;
+          spirvOpts.useDxLayout = opts.VkUseDxLayout;
           spirvOpts.enableReflect = opts.SpvEnableReflect;
           spirvOpts.ignoreUnusedResources = opts.VkIgnoreUnusedResources;
           spirvOpts.defaultRowMajor = opts.DefaultRowMajor;

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

@@ -1418,6 +1418,15 @@ TEST_F(FileTest, VulkanLayoutCBufferPackOffsetError) {
   runFileTest("vk.layout.cbuffer.packoffset.error.hlsl", Expect::Failure);
 }
 
+TEST_F(FileTest, VulkanLayoutFxcRulesSBuffer) {
+  // structured buffers with fxc layout rules
+  runFileTest("vk.layout.sbuffer.fxc.hlsl");
+}
+TEST_F(FileTest, VulkanLayoutFxcRulesCBuffer) {
+  // cbuffer/tbuffer/ConstantBuffer/TextureBuffer with fxc layout rules
+  runFileTest("vk.layout.cbuffer.fxc.hlsl");
+}
+
 TEST_F(FileTest, VulkanSubpassInput) { runFileTest("vk.subpass-input.hlsl"); }
 TEST_F(FileTest, VulkanSubpassInputBinding) {
   runFileTest("vk.subpass-input.binding.hlsl");