Bläddra i källkod

[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 7 år sedan
förälder
incheckning
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
 ``-fspv-extension=<extension>`` command-line option. Only extensions supplied
 via ``-fspv-extension=`` will be used. If that does not suffice, errors will
 via ``-fspv-extension=`` will be used. If that does not suffice, errors will
 be emitted explaining what additional extensions are required to translate what
 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``.
 you can use ``-fspv-extension=KHR``.
 
 
 Legalization, optimization, validation
 Legalization, optimization, validation
@@ -662,7 +662,10 @@ alignment:
    the alignment will be set to 16 bytes.
    the alignment will be set to 16 bytes.
 
 
 To use the conventional GLSL ``std140``/``std430`` rules for resources,
 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
 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>`_.
@@ -2644,6 +2647,7 @@ codegen for Vulkan:
   in question.
   in question.
 - ``-fvk-use-glsl-layout``: Uses conventional GLSL ``std140``/``std430`` layout
 - ``-fvk-use-glsl-layout``: Uses conventional GLSL ``std140``/``std430`` layout
   rules for resources.
   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.
 - ``-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

@@ -164,6 +164,7 @@ public:
   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
   bool VkUseGlslLayout;                    // OPT_fvk_use_glsl_layout
+  bool VkUseDxLayout;                      // OPT_fvk_use_dx_layout
   bool SpvEnableReflect;                   // OPT_fspv_reflect
   bool SpvEnableReflect;                   // OPT_fspv_reflect
   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

+ 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]>,
 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]>,
 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]>,
 def fspv_reflect: Flag<["-"], "fspv-reflect">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
   HelpText<"Emit additional SPIR-V instructions to aid reflection">;
   HelpText<"Emit additional SPIR-V instructions to aid reflection">;
 def fspv_extension_EQ : Joined<["-"], "fspv-extension=">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
 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);
   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.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.SpvEnableReflect = Args.hasFlag(OPT_fspv_reflect, 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);
 
 
@@ -532,6 +533,7 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
   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_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_fspv_reflect, 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() ||

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

@@ -13,6 +13,19 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/StringRef.h"
 
 
 namespace clang {
 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.
 /// Structs for controlling behaviors of SPIR-V codegen.
 struct EmitSPIRVOptions {
 struct EmitSPIRVOptions {
   /// Disable legalization and optimization and emit raw SPIR-V
   /// Disable legalization and optimization and emit raw SPIR-V
@@ -21,6 +34,7 @@ struct EmitSPIRVOptions {
   bool disableValidation;
   bool disableValidation;
   bool invertY;
   bool invertY;
   bool useGlslLayout;
   bool useGlslLayout;
+  bool useDxLayout;
   bool ignoreUnusedResources;
   bool ignoreUnusedResources;
   bool enable16BitTypes;
   bool enable16BitTypes;
   bool enableReflect;
   bool enableReflect;
@@ -31,6 +45,12 @@ struct EmitSPIRVOptions {
   llvm::SmallVector<uint32_t, 4> uShift;
   llvm::SmallVector<uint32_t, 4> uShift;
   llvm::SmallVector<llvm::StringRef, 4> allowedExtensions;
   llvm::SmallVector<llvm::StringRef, 4> allowedExtensions;
   llvm::StringRef targetEnv;
   llvm::StringRef targetEnv;
+  spirv::LayoutRule cBufferLayoutRule;
+  spirv::LayoutRule tBufferLayoutRule;
+  spirv::LayoutRule sBufferLayoutRule;
+
+  // Initializes dependent fields appropriately
+  void Initialize();
 };
 };
 } // end namespace clang
 } // end namespace clang
 
 

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

@@ -8,6 +8,7 @@ add_clang_library(clangSPIRV
   DeclResultIdMapper.cpp
   DeclResultIdMapper.cpp
   Decoration.cpp
   Decoration.cpp
   EmitSPIRVAction.cpp
   EmitSPIRVAction.cpp
+  EmitSPIRVOptions.cpp
   FeatureManager.cpp
   FeatureManager.cpp
   GlPerVertex.cpp
   GlPerVertex.cpp
   InitListHandler.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" ||
     if (typeName == "StructuredBuffer" || typeName == "ByteAddressBuffer" ||
         typeName == "RWByteAddressBuffer") {
         typeName == "RWByteAddressBuffer") {
       storageClass = spv::StorageClass::Uniform;
       storageClass = spv::StorageClass::Uniform;
-      rule = LayoutRule::GLSLStd430;
+      rule = spirvOptions.sBufferLayoutRule;
     } else if (typeName == "RWStructuredBuffer" ||
     } else if (typeName == "RWStructuredBuffer" ||
                typeName == "AppendStructuredBuffer" ||
                typeName == "AppendStructuredBuffer" ||
                typeName == "ConsumeStructuredBuffer") {
                typeName == "ConsumeStructuredBuffer") {
       storageClass = spv::StorageClass::Uniform;
       storageClass = spv::StorageClass::Uniform;
-      rule = LayoutRule::GLSLStd430;
+      rule = spirvOptions.sBufferLayoutRule;
       isACRWSBuffer = true;
       isACRWSBuffer = true;
     }
     }
   } else {
   } else {
@@ -492,9 +492,11 @@ uint32_t DeclResultIdMapper::createStructOrStructArrayVarOfExplicitLayout(
   const bool forGlobals = usageKind == ContextUsageKind::Globals;
   const bool forGlobals = usageKind == ContextUsageKind::Globals;
 
 
   auto &context = *theBuilder.getSPIRVContext();
   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)
   const auto *blockDec = forTBuffer ? Decoration::getBufferBlock(context)
                                     : Decoration::getBlock(context);
                                     : Decoration::getBlock(context);
 
 
@@ -572,8 +574,8 @@ uint32_t DeclResultIdMapper::createCTBuffer(const HLSLBufferDecl *decl) {
     astDecls[varDecl] =
     astDecls[varDecl] =
         SpirvEvalInfo(bufferVar)
         SpirvEvalInfo(bufferVar)
             .setStorageClass(spv::StorageClass::Uniform)
             .setStorageClass(spv::StorageClass::Uniform)
-            .setLayoutRule(decl->isCBuffer() ? LayoutRule::GLSLStd140
-                                             : LayoutRule::GLSLStd430);
+            .setLayoutRule(decl->isCBuffer() ? spirvOptions.cBufferLayoutRule
+                                             : spirvOptions.tBufferLayoutRule);
     astDecls[varDecl].indexInCTBuffer = index++;
     astDecls[varDecl].indexInCTBuffer = index++;
   }
   }
   resourceVars.emplace_back(
   resourceVars.emplace_back(
@@ -612,8 +614,8 @@ uint32_t DeclResultIdMapper::createCTBuffer(const VarDecl *decl) {
   astDecls[decl] =
   astDecls[decl] =
       SpirvEvalInfo(bufferVar)
       SpirvEvalInfo(bufferVar)
           .setStorageClass(spv::StorageClass::Uniform)
           .setStorageClass(spv::StorageClass::Uniform)
-          .setLayoutRule(context->isCBuffer() ? LayoutRule::GLSLStd140
-                                              : LayoutRule::GLSLStd430);
+          .setLayoutRule(context->isCBuffer() ? spirvOptions.cBufferLayoutRule
+                                              : spirvOptions.tBufferLayoutRule);
   resourceVars.emplace_back(
   resourceVars.emplace_back(
       bufferVar, ResourceVar::Category::Other, getResourceBinding(context),
       bufferVar, ResourceVar::Category::Other, getResourceBinding(context),
       decl->getAttr<VKBindingAttr>(), decl->getAttr<VKCounterBindingAttr>());
       decl->getAttr<VKBindingAttr>(), decl->getAttr<VKCounterBindingAttr>());
@@ -635,7 +637,7 @@ uint32_t DeclResultIdMapper::createPushConstant(const VarDecl *decl) {
   // Register the VarDecl
   // Register the VarDecl
   astDecls[decl] = SpirvEvalInfo(var)
   astDecls[decl] = SpirvEvalInfo(var)
                        .setStorageClass(spv::StorageClass::PushConstant)
                        .setStorageClass(spv::StorageClass::PushConstant)
-                       .setLayoutRule(LayoutRule::GLSLStd430);
+                       .setLayoutRule(spirvOptions.sBufferLayoutRule);
   // Do not push this variable into resourceVars since it does not need
   // Do not push this variable into resourceVars since it does not need
   // descriptor set.
   // descriptor set.
 
 
@@ -670,7 +672,7 @@ void DeclResultIdMapper::createGlobalsCBuffer(const VarDecl *var) {
 
 
       astDecls[varDecl] = SpirvEvalInfo(globals)
       astDecls[varDecl] = SpirvEvalInfo(globals)
                               .setStorageClass(spv::StorageClass::Uniform)
                               .setStorageClass(spv::StorageClass::Uniform)
-                              .setLayoutRule(LayoutRule::GLSLStd140);
+                              .setLayoutRule(spirvOptions.cBufferLayoutRule);
       astDecls[varDecl].indexInCTBuffer = index++;
       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
 } // namespace
 
 
-SPIRVEmitter::SPIRVEmitter(CompilerInstance &ci,
-                           const EmitSPIRVOptions &options)
+SPIRVEmitter::SPIRVEmitter(CompilerInstance &ci, EmitSPIRVOptions &options)
     : theCompilerInstance(ci), astContext(ci.getASTContext()),
     : theCompilerInstance(ci), astContext(ci.getASTContext()),
       diags(ci.getDiagnostics()), spirvOptions(options),
       diags(ci.getDiagnostics()), spirvOptions(options),
       entryFunctionName(ci.getCodeGenOpts().HLSLEntryFunction),
       entryFunctionName(ci.getCodeGenOpts().HLSLEntryFunction),
@@ -523,7 +522,7 @@ SPIRVEmitter::SPIRVEmitter(CompilerInstance &ci,
       theBuilder(&theContext, &featureManager, options.enableReflect),
       theBuilder(&theContext, &featureManager, options.enableReflect),
       typeTranslator(astContext, theBuilder, diags, options),
       typeTranslator(astContext, theBuilder, diags, options),
       declIdMapper(shaderModel, astContext, theBuilder, typeTranslator,
       declIdMapper(shaderModel, astContext, theBuilder, typeTranslator,
-                   featureManager, spirvOptions),
+                   featureManager, options),
       entryFunctionId(0), curFunction(nullptr), curThis(0),
       entryFunctionId(0), curFunction(nullptr), curThis(0),
       seenPushConstantAt(), isSpecConstantMode(false),
       seenPushConstantAt(), isSpecConstantMode(false),
       needsLegalization(false) {
       needsLegalization(false) {
@@ -533,6 +532,12 @@ SPIRVEmitter::SPIRVEmitter(CompilerInstance &ci,
   if (options.invertY && !shaderModel.IsVS() && !shaderModel.IsDS() &&
   if (options.invertY && !shaderModel.IsVS() && !shaderModel.IsDS() &&
       !shaderModel.IsGS())
       !shaderModel.IsGS())
     emitError("-fvk-invert-y can only be used in VS/DS/GS", {});
     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) {
 void SPIRVEmitter::HandleTranslationUnit(ASTContext &context) {
@@ -909,7 +914,7 @@ bool SPIRVEmitter::loadIfAliasVarRef(const Expr *varExpr, SpirvEvalInfo &info) {
       info.setResultId(theBuilder.createLoad(ptrType, info));
       info.setResultId(theBuilder.createLoad(ptrType, info));
 
 
     info.setStorageClass(spv::StorageClass::Uniform)
     info.setStorageClass(spv::StorageClass::Uniform)
-        .setLayoutRule(LayoutRule::GLSLStd430)
+        .setLayoutRule(spirvOptions.sBufferLayoutRule)
         // Now it is a pointer to the global resource, which is lvalue.
         // Now it is a pointer to the global resource, which is lvalue.
         .setRValue(false)
         .setRValue(false)
         // Set to false to indicate that we've performed dereference over the
         // 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.
     // size of the struct) must also be written to the second argument.
     uint32_t size = 0, stride = 0;
     uint32_t size = 0, stride = 0;
     std::tie(std::ignore, size) = typeTranslator.getAlignmentAndSize(
     std::tie(std::ignore, size) = typeTranslator.getAlignmentAndSize(
-        type, LayoutRule::GLSLStd430, &stride);
+        type, spirvOptions.sBufferLayoutRule, &stride);
     const auto sizeId = theBuilder.getConstantUint32(size);
     const auto sizeId = theBuilder.getConstantUint32(size);
     theBuilder.createStore(doExpr(expr->getArg(1)), sizeId);
     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.
 /// through the AST is done manually instead of using ASTConsumer's harness.
 class SPIRVEmitter : public ASTConsumer {
 class SPIRVEmitter : public ASTConsumer {
 public:
 public:
-  SPIRVEmitter(CompilerInstance &ci, const EmitSPIRVOptions &options);
+  SPIRVEmitter(CompilerInstance &ci, EmitSPIRVOptions &options);
 
 
   void HandleTranslationUnit(ASTContext &context) override;
   void HandleTranslationUnit(ASTContext &context) override;
 
 
@@ -904,7 +904,7 @@ private:
   ASTContext &astContext;
   ASTContext &astContext;
   DiagnosticsEngine &diags;
   DiagnosticsEngine &diags;
 
 
-  EmitSPIRVOptions spirvOptions;
+  const EmitSPIRVOptions &spirvOptions;
 
 
   /// Entry function name and shader stage. Both of them are derived from the
   /// Entry function name and shader stage. Both of them are derived from the
   /// command line and should be const.
   /// command line and should be const.

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

@@ -19,13 +19,6 @@
 namespace clang {
 namespace clang {
 namespace spirv {
 namespace spirv {
 
 
-/// Memory layout rules
-enum class LayoutRule {
-  Void,
-  GLSLStd140,
-  GLSLStd430,
-};
-
 /// Struct contains SPIR-V information from evaluating a Clang AST node.
 /// 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:
 /// 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; }
 inline bool isPow2(int val) { return (val & (val - 1)) == 0; }
 
 
 /// Rounds the given value up to the given power of 2.
 /// 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);
   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
 /// 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) {
 bool TypeTranslator::isOpaqueArrayType(QualType type) {
-  if (const auto* arrayType = type->getAsArrayTypeUnsafe())
+  if (const auto *arrayType = type->getAsArrayTypeUnsafe())
     return isOpaqueType(arrayType->getElementType());
     return isOpaqueType(arrayType->getElementType());
   return false;
   return false;
 }
 }
@@ -1196,8 +1196,13 @@ TypeTranslator::getLayoutDecorations(const DeclContext *decl, LayoutRule rule) {
     // The next avaiable location after layouting the previos members
     // The next avaiable location after layouting the previos members
     const uint32_t nextLoc = offset;
     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.
     // The vk::offset attribute takes precedence over all.
     if (const auto *offsetAttr = field->getAttr<VKOffsetAttr>()) {
     if (const auto *offsetAttr = field->getAttr<VKOffsetAttr>()) {
@@ -1326,7 +1331,7 @@ uint32_t TypeTranslator::translateResourceType(QualType type, LayoutRule rule,
     bool asAlias = false;
     bool asAlias = false;
     if (rule == LayoutRule::Void) {
     if (rule == LayoutRule::Void) {
       asAlias = true;
       asAlias = true;
-      rule = LayoutRule::GLSLStd430;
+      rule = spirvOptions.sBufferLayoutRule;
     }
     }
 
 
     auto &context = *theBuilder.getSPIRVContext();
     auto &context = *theBuilder.getSPIRVContext();
@@ -1468,30 +1473,28 @@ void TypeTranslator::alignUsingHLSLRelaxedLayout(QualType fieldType,
                                                  uint32_t fieldSize,
                                                  uint32_t fieldSize,
                                                  uint32_t *fieldAlignment,
                                                  uint32_t *fieldAlignment,
                                                  uint32_t *currentOffset) {
                                                  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.
   // Adjust according to HLSL relaxed layout rules.
   // Bump to 4-component vector alignment if there is a bad straddle
   // Bump to 4-component vector alignment if there is a bad straddle
-  if (!spirvOptions.useGlslLayout && fieldIsVecType &&
+  if (fieldIsVecType &&
       improperStraddle(fieldType, fieldSize, *currentOffset)) {
       improperStraddle(fieldType, fieldSize, *currentOffset)) {
     *fieldAlignment = kStd140Vec4Alignment;
     *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
   // 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).
   //     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);
   const auto desugaredType = desugarType(type);
   if (desugaredType != type) {
   if (desugaredType != type) {
@@ -1559,8 +1586,6 @@ TypeTranslator::getAlignmentAndSize(QualType type, LayoutRule rule,
     if (isScalarType(type, &ty))
     if (isScalarType(type, &ty))
       if (const auto *builtinType = ty->getAs<BuiltinType>())
       if (const auto *builtinType = ty->getAs<BuiltinType>())
         switch (builtinType->getKind()) {
         switch (builtinType->getKind()) {
-        case BuiltinType::Void:
-          return {0, 0};
         case BuiltinType::Bool:
         case BuiltinType::Bool:
         case BuiltinType::Int:
         case BuiltinType::Int:
         case BuiltinType::UInt:
         case BuiltinType::UInt:
@@ -1581,10 +1606,13 @@ TypeTranslator::getAlignmentAndSize(QualType type, LayoutRule rule,
     QualType elemType = {};
     QualType elemType = {};
     uint32_t elemCount = {};
     uint32_t elemCount = {};
     if (isVectorType(type, &elemType, &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;
     uint32_t rowCount = 0, colCount = 0;
     if (isMxNMatrix(type, &elemType, &rowCount, &colCount)) {
     if (isMxNMatrix(type, &elemType, &rowCount, &colCount)) {
       uint32_t alignment = 0, size = 0;
       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:
       // Matrices are treated as arrays of vectors:
       // The base alignment and array stride are set to match the base alignment
       // 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);
       bool isRowMajor = isRowMajorMatrix(type);
 
 
       const uint32_t vecStorageSize = isRowMajor ? colCount : rowCount;
       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);
       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;
       *stride = alignment;
       size = (isRowMajor ? rowCount : colCount) * alignment;
       size = (isRowMajor ? rowCount : colCount) * alignment;
@@ -1629,8 +1665,13 @@ TypeTranslator::getAlignmentAndSize(QualType type, LayoutRule rule,
       std::tie(memberAlignment, memberSize) =
       std::tie(memberAlignment, memberSize) =
           getAlignmentAndSize(field->getType(), rule, stride);
           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
       // 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...
@@ -1638,36 +1679,56 @@ TypeTranslator::getAlignmentAndSize(QualType type, LayoutRule rule,
       structSize += memberSize;
       structSize += memberSize;
     }
     }
 
 
-    if (rule == LayoutRule::GLSLStd140) {
+    if (rule == LayoutRule::GLSLStd140 ||
+        rule == LayoutRule::RelaxedGLSLStd140) {
       // ... and rounded up to the base alignment of a vec4.
       // ... 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};
     return {maxAlignment, structSize};
   }
   }
 
 
   // Rule 4, 6, 8, and 10
   // Rule 4, 6, 8, and 10
   if (const auto *arrayType = astContext.getAsConstantArrayType(type)) {
   if (const auto *arrayType = astContext.getAsConstantArrayType(type)) {
+    const auto elemCount = arrayType->getSize().getZExtValue();
     uint32_t alignment = 0, size = 0;
     uint32_t alignment = 0, size = 0;
     std::tie(alignment, size) =
     std::tie(alignment, size) =
         getAlignmentAndSize(arrayType->getElementType(), rule, stride);
         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
       // 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
       // of a single array element, according to rules 1, 2, and 3, and rounded
       // up to the base alignment of a vec4.
       // 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};
     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.disableValidation = opts.DisableValidation;
           spirvOpts.invertY = opts.VkInvertY;
           spirvOpts.invertY = opts.VkInvertY;
           spirvOpts.useGlslLayout = opts.VkUseGlslLayout;
           spirvOpts.useGlslLayout = opts.VkUseGlslLayout;
+          spirvOpts.useDxLayout = opts.VkUseDxLayout;
           spirvOpts.enableReflect = opts.SpvEnableReflect;
           spirvOpts.enableReflect = opts.SpvEnableReflect;
           spirvOpts.ignoreUnusedResources = opts.VkIgnoreUnusedResources;
           spirvOpts.ignoreUnusedResources = opts.VkIgnoreUnusedResources;
           spirvOpts.defaultRowMajor = opts.DefaultRowMajor;
           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);
   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, VulkanSubpassInput) { runFileTest("vk.subpass-input.hlsl"); }
 TEST_F(FileTest, VulkanSubpassInputBinding) {
 TEST_F(FileTest, VulkanSubpassInputBinding) {
   runFileTest("vk.subpass-input.binding.hlsl");
   runFileTest("vk.subpass-input.binding.hlsl");