summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/command-line-slangc-reference.mdbin77970 -> 78354 bytes
-rw-r--r--include/slang.h3
-rw-r--r--source/slang-record-replay/util/emum-to-string.h1
-rw-r--r--source/slang/slang-compiler-options.cpp1
-rw-r--r--source/slang/slang-compiler-options.h5
-rwxr-xr-xsource/slang/slang-compiler.h1
-rw-r--r--source/slang/slang-emit-spirv.cpp18
-rw-r--r--source/slang/slang-ir-layout.cpp35
-rw-r--r--source/slang/slang-ir-layout.h7
-rw-r--r--source/slang/slang-ir-lower-buffer-element-type.cpp10
-rw-r--r--source/slang/slang-ir.h1
-rw-r--r--source/slang/slang-options.cpp11
-rw-r--r--source/slang/slang-type-layout.cpp38
-rw-r--r--source/slang/slang.cpp5
-rw-r--r--tests/spirv/cbuffer-dx-layout-1.slang76
-rw-r--r--tests/spirv/cbuffer-dx-layout-2.slang86
-rw-r--r--tests/spirv/cbuffer-dx-layout-3.slang46
-rw-r--r--tests/spirv/cbuffer-dx-layout-4.slang52
-rw-r--r--tests/spirv/cbuffer-not-dx-layout.slang56
-rw-r--r--tests/spirv/structured-buffer-dx-layout.slang57
-rw-r--r--tests/spirv/tbuffer-dx-layout-1.slang73
21 files changed, 571 insertions, 11 deletions
diff --git a/docs/command-line-slangc-reference.md b/docs/command-line-slangc-reference.md
index 3e25cdce6..b7cef7a53 100644
--- a/docs/command-line-slangc-reference.md
+++ b/docs/command-line-slangc-reference.md
Binary files differ
diff --git a/include/slang.h b/include/slang.h
index ea62a829f..8f4d53a0d 100644
--- a/include/slang.h
+++ b/include/slang.h
@@ -958,6 +958,7 @@ extern "C"
// precompiled modules if it is up-to-date with its source.
EmbedDXIL, // bool
+ ForceDXLayout, // bool
CountOf,
};
@@ -4837,6 +4838,8 @@ namespace slang
virtual SLANG_NO_THROW void SLANG_MCALL setTargetEmbedDXIL(
int targetIndex,
bool value) = 0;
+
+ virtual SLANG_NO_THROW void SLANG_MCALL setTargetForceDXLayout(int targetIndex, bool value) = 0;
};
#define SLANG_UUID_ICompileRequest ICompileRequest::getTypeGuid()
diff --git a/source/slang-record-replay/util/emum-to-string.h b/source/slang-record-replay/util/emum-to-string.h
index f06631719..3c7568818 100644
--- a/source/slang-record-replay/util/emum-to-string.h
+++ b/source/slang-record-replay/util/emum-to-string.h
@@ -175,6 +175,7 @@ namespace SlangRecord
CASE(VulkanUseGLLayout);
CASE(VulkanEmitReflection);
CASE(GLSLForceScalarLayout);
+ CASE(ForceDXLayout);
CASE(EnableEffectAnnotations);
CASE(EmitSpirvViaGLSL);
CASE(EmitSpirvDirectly);
diff --git a/source/slang/slang-compiler-options.cpp b/source/slang/slang-compiler-options.cpp
index ea2593713..3325a313a 100644
--- a/source/slang/slang-compiler-options.cpp
+++ b/source/slang/slang-compiler-options.cpp
@@ -110,6 +110,7 @@ namespace Slang
break;
case CompilerOptionName::EmitSpirvDirectly:
case CompilerOptionName::GLSLForceScalarLayout:
+ case CompilerOptionName::ForceDXLayout:
case CompilerOptionName::MatrixLayoutRow:
case CompilerOptionName::MatrixLayoutColumn:
case CompilerOptionName::VulkanInvertY:
diff --git a/source/slang/slang-compiler-options.h b/source/slang/slang-compiler-options.h
index dae6d49e5..f2bf467e2 100644
--- a/source/slang/slang-compiler-options.h
+++ b/source/slang/slang-compiler-options.h
@@ -346,6 +346,11 @@ namespace Slang
return getBoolOption(CompilerOptionName::GLSLForceScalarLayout);
}
+ bool shouldUseDXLayout()
+ {
+ return getBoolOption(CompilerOptionName::ForceDXLayout);
+ }
+
bool shouldDumpIntermediates()
{
return getBoolOption(CompilerOptionName::DumpIntermediates);
diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h
index ac85f175e..5ebefb888 100755
--- a/source/slang/slang-compiler.h
+++ b/source/slang/slang-compiler.h
@@ -2807,6 +2807,7 @@ namespace Slang
virtual SLANG_NO_THROW void SLANG_MCALL setTargetFloatingPointMode(int targetIndex, SlangFloatingPointMode mode) SLANG_OVERRIDE;
virtual SLANG_NO_THROW void SLANG_MCALL setTargetMatrixLayoutMode(int targetIndex, SlangMatrixLayoutMode mode) SLANG_OVERRIDE;
virtual SLANG_NO_THROW void SLANG_MCALL setTargetForceGLSLScalarBufferLayout(int targetIndex, bool value) SLANG_OVERRIDE;
+ virtual SLANG_NO_THROW void SLANG_MCALL setTargetForceDXLayout(int targetIndex, bool value) SLANG_OVERRIDE;
virtual SLANG_NO_THROW void SLANG_MCALL setTargetGenerateWholeProgram(int targetIndex, bool value) SLANG_OVERRIDE;
virtual SLANG_NO_THROW void SLANG_MCALL setTargetEmbedDXIL(int targetIndex, bool value) SLANG_OVERRIDE;
virtual SLANG_NO_THROW void SLANG_MCALL setMatrixLayoutMode(SlangMatrixLayoutMode mode) SLANG_OVERRIDE;
diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp
index 20cbbac02..8f4501c2b 100644
--- a/source/slang/slang-emit-spirv.cpp
+++ b/source/slang/slang-emit-spirv.cpp
@@ -3993,7 +3993,7 @@ struct SPIRVEmitContext
auto rule = IRTypeLayoutRules::get(layoutRuleName);
IRSizeAndAlignment elementSizeAlignment;
getSizeAndAlignment(m_targetProgram->getOptionSet(), rule, matrixType->getElementType(), &elementSizeAlignment);
-
+ IRIntegerValue matrixMinorVectorCount = 0;
// Reminder: the meaning of row/column major layout
// in our semantics is the *opposite* of what GLSL/SPIRV
// calls them, because what they call "columns"
@@ -4007,10 +4007,7 @@ struct SPIRVEmitContext
spvStructID,
SpvLiteralInteger::from32(id),
SpvDecorationRowMajor);
-
- auto vectorSize = rule->getVectorSizeAndAlignment(elementSizeAlignment, getIntVal(matrixType->getRowCount()));
- vectorSize = rule->alignCompositeElement(vectorSize);
- matrixStride = vectorSize.getStride();
+ matrixMinorVectorCount = getIntVal(matrixType->getRowCount());
}
else
{
@@ -4020,12 +4017,15 @@ struct SPIRVEmitContext
spvStructID,
SpvLiteralInteger::from32(id),
SpvDecorationColMajor);
-
- auto vectorSize = rule->getVectorSizeAndAlignment(elementSizeAlignment, getIntVal(matrixType->getColumnCount()));
- vectorSize = rule->alignCompositeElement(vectorSize);
- matrixStride = vectorSize.getStride();
+ matrixMinorVectorCount = getIntVal(matrixType->getColumnCount());
}
+ // We need the size of our vector. To get the stride we need to know how 'big'
+ // each vector element is inside an array, due to this we align our vector
+ // as if a composite.
+ auto vectorSize = rule->getVectorSizeAndAlignment(elementSizeAlignment, matrixMinorVectorCount);
+ vectorSize = rule->alignCompositeElement(vectorSize);
+ matrixStride = vectorSize.getStride();
emitOpMemberDecorateMatrixStride(
getSection(SpvLogicalSectionID::Annotations),
nullptr,
diff --git a/source/slang/slang-ir-layout.cpp b/source/slang/slang-ir-layout.cpp
index 6a4e9360a..3a2471930 100644
--- a/source/slang/slang-ir-layout.cpp
+++ b/source/slang/slang-ir-layout.cpp
@@ -443,6 +443,33 @@ struct NaturalLayoutRules : IRTypeLayoutRules
}
};
+struct ConstantBufferLayoutRules : IRTypeLayoutRules
+{
+ ConstantBufferLayoutRules()
+ {
+ ruleName = IRTypeLayoutRuleName::D3DConstantBuffer;
+ }
+
+ /// Next member only aligns to 16 if the next member is an array/matrix/struct
+ virtual IRSizeAndAlignment alignCompositeElement(IRSizeAndAlignment currentSize)
+ {
+ // Matrix/Array/Struct should be aligned on a new register
+ return IRSizeAndAlignment(currentSize.size, 16);
+ }
+
+ virtual IRIntegerValue adjustOffsetForNextAggregateMember(IRIntegerValue currentSize, IRIntegerValue lastElementAlignment)
+ {
+ SLANG_UNUSED(lastElementAlignment);
+ return currentSize;
+ }
+
+ virtual IRSizeAndAlignment getVectorSizeAndAlignment(IRSizeAndAlignment element, IRIntegerValue count)
+ {
+ IRIntegerValue countForAlignment = count;
+ return IRSizeAndAlignment((int)(element.size * count), (int)(element.size * countForAlignment));
+ }
+};
+
struct Std430LayoutRules : IRTypeLayoutRules
{
Std430LayoutRules()
@@ -534,6 +561,13 @@ IRTypeLayoutRules* IRTypeLayoutRules::getNatural()
static NaturalLayoutRules rules;
return &rules;
}
+
+IRTypeLayoutRules* IRTypeLayoutRules::getConstantBuffer()
+{
+ static ConstantBufferLayoutRules rules;
+ return &rules;
+}
+
IRTypeLayoutRules* IRTypeLayoutRules::get(IRTypeLayoutRuleName name)
{
switch (name)
@@ -541,6 +575,7 @@ IRTypeLayoutRules* IRTypeLayoutRules::get(IRTypeLayoutRuleName name)
case IRTypeLayoutRuleName::Std430: return getStd430();
case IRTypeLayoutRuleName::Std140: return getStd140();
case IRTypeLayoutRuleName::Natural: return getNatural();
+ case IRTypeLayoutRuleName::D3DConstantBuffer: return getConstantBuffer();
default: return nullptr;
}
}
diff --git a/source/slang/slang-ir-layout.h b/source/slang/slang-ir-layout.h
index 09da2a8f9..c7e5d2b31 100644
--- a/source/slang/slang-ir-layout.h
+++ b/source/slang/slang-ir-layout.h
@@ -58,12 +58,19 @@ struct IRTypeLayoutRules
{
public:
IRTypeLayoutRuleName ruleName;
+
+ /// Align composite based on rule. Type is aligned assuming
+ /// it is apart of a composite (array, struct, matrix, etc...)
virtual IRSizeAndAlignment alignCompositeElement(IRSizeAndAlignment elementSize) = 0;
+
+ /// Get alignment and size of a vector given components of vector.
+ /// This alignment is not assuming this vector is a member of a struct.
virtual IRSizeAndAlignment getVectorSizeAndAlignment(IRSizeAndAlignment element, IRIntegerValue count) = 0;
virtual IRIntegerValue adjustOffsetForNextAggregateMember(IRIntegerValue currentSize, IRIntegerValue lastElementAlignment) = 0;
static IRTypeLayoutRules* getStd430();
static IRTypeLayoutRules* getStd140();
static IRTypeLayoutRules* getNatural();
+ static IRTypeLayoutRules* getConstantBuffer();
static IRTypeLayoutRules* get(IRTypeLayoutRuleName name);
};
diff --git a/source/slang/slang-ir-lower-buffer-element-type.cpp b/source/slang/slang-ir-lower-buffer-element-type.cpp
index cc24a0e81..a480ae673 100644
--- a/source/slang/slang-ir-lower-buffer-element-type.cpp
+++ b/source/slang/slang-ir-lower-buffer-element-type.cpp
@@ -899,6 +899,16 @@ namespace Slang
if (target->getOptionSet().shouldUseScalarLayout())
return IRTypeLayoutRules::getNatural();
+ if (target->getOptionSet().shouldUseDXLayout())
+ {
+ if (as<IRUniformParameterGroupType>(bufferType))
+ {
+ return IRTypeLayoutRules::getConstantBuffer();
+ }
+ else
+ return IRTypeLayoutRules::getNatural();
+ }
+
// The default behavior is to use std140 for constant buffers and std430 for other buffers.
switch (bufferType->getOp())
{
diff --git a/source/slang/slang-ir.h b/source/slang/slang-ir.h
index 4a3a04404..036c7f3a7 100644
--- a/source/slang/slang-ir.h
+++ b/source/slang/slang-ir.h
@@ -564,6 +564,7 @@ enum class IRTypeLayoutRuleName
Scalar = Natural,
Std430,
Std140,
+ D3DConstantBuffer,
_Count,
};
diff --git a/source/slang/slang-options.cpp b/source/slang/slang-options.cpp
index 33103442d..12b32998f 100644
--- a/source/slang/slang-options.cpp
+++ b/source/slang/slang-options.cpp
@@ -400,6 +400,7 @@ void initCommandOptions(CommandOptions& options)
{ OptionKind::GLSLForceScalarLayout,
"-force-glsl-scalar-layout,-fvk-use-scalar-layout", nullptr,
"Make data accessed through ConstantBuffer, ParameterBlock, StructuredBuffer, ByteAddressBuffer and general pointers follow the 'scalar' layout when targeting GLSL or SPIRV."},
+ { OptionKind::ForceDXLayout, "-fvk-use-dx-layout", nullptr, "Pack members using FXCs member packing rules when targeting GLSL or SPIRV." },
{ OptionKind::VulkanBindShift, vkShiftNames.getBuffer(), "-fvk-<vulkan-shift>-shift <N> <space>",
"For example '-fvk-b-shift <N> <space>' shifts by N the inferred binding numbers for all resources in 'b' registers of space <space>. "
"For a resource attached with :register(bX, <space>) but not [vk::binding(...)], "
@@ -2054,6 +2055,11 @@ SlangResult OptionsParser::_parse(
getCurrentTarget()->optionSet.add(CompilerOptionName::GLSLForceScalarLayout, true);
break;
}
+ case OptionKind::ForceDXLayout:
+ {
+ getCurrentTarget()->optionSet.add(CompilerOptionName::ForceDXLayout, true);
+ break;
+ }
case OptionKind::EnableEffectAnnotations:
{
m_compileRequest->setEnableEffectAnnotations(true);
@@ -2780,6 +2786,11 @@ SlangResult OptionsParser::_parse(
m_compileRequest->setTargetForceGLSLScalarBufferLayout(targetID, true);
}
+ if (rawTarget.optionSet.shouldUseDXLayout())
+ {
+ m_compileRequest->setTargetForceDXLayout(targetID, true);
+ }
+
if (rawTarget.optionSet.getBoolOption(CompilerOptionName::GenerateWholeProgram))
{
m_compileRequest->setTargetGenerateWholeProgram(targetID, true);
diff --git a/source/slang/slang-type-layout.cpp b/source/slang/slang-type-layout.cpp
index f5fbfafdf..7d6d047d3 100644
--- a/source/slang/slang-type-layout.cpp
+++ b/source/slang/slang-type-layout.cpp
@@ -400,6 +400,12 @@ struct HLSLConstantBufferLayoutRulesImpl : DefaultLayoutRulesImpl
}
};
+/// GLSL fvk-use-dx-layout for `ShaderResource`
+struct FXCShaderResourceLayoutRulesImpl : DefaultLayoutRulesImpl
+{
+ // Currently this FXC layout is equal to how we compute 'DefaultLayoutRulesImpl'
+};
+
/* CPU layout requires that all sizes are a multiple of alignment.
*/
struct CPULayoutRulesImpl : DefaultLayoutRulesImpl
@@ -894,6 +900,7 @@ struct CUDARayTracingLayoutRulesImpl : DefaultVaryingLayoutRulesImpl
DefaultLayoutRulesImpl kDefaultLayoutRulesImpl;
Std140LayoutRulesImpl kStd140LayoutRulesImpl;
Std430LayoutRulesImpl kStd430LayoutRulesImpl;
+FXCShaderResourceLayoutRulesImpl kFXCShaderResourceLayoutRulesImpl;
HLSLConstantBufferLayoutRulesImpl kHLSLConstantBufferLayoutRulesImpl;
HLSLStructuredBufferLayoutRulesImpl kHLSLStructuredBufferLayoutRulesImpl;
@@ -1206,6 +1213,18 @@ LayoutRulesImpl kScalarLayoutRulesImpl_ = {
&kGLSLObjectLayoutRulesImpl,
};
+LayoutRulesImpl kFXCShaderResourceLayoutRulesFamilyImpl = {
+ &kGLSLLayoutRulesFamilyImpl,
+ &kFXCShaderResourceLayoutRulesImpl,
+ &kGLSLObjectLayoutRulesImpl,
+};
+
+LayoutRulesImpl kFXCConstantBufferLayoutRulesFamilyImpl = {
+ &kGLSLLayoutRulesFamilyImpl,
+ &kHLSLConstantBufferLayoutRulesImpl,
+ &kGLSLObjectLayoutRulesImpl,
+};
+
LayoutRulesImpl kGLSLAnyValueLayoutRulesImpl_ = {
&kGLSLLayoutRulesFamilyImpl,
&kDefaultLayoutRulesImpl,
@@ -1300,6 +1319,9 @@ LayoutRulesImpl* GLSLLayoutRulesFamilyImpl::getConstantBufferRules(CompilerOptio
{
if (compilerOptions.shouldUseScalarLayout())
return &kScalarLayoutRulesImpl_;
+ else if (compilerOptions.shouldUseDXLayout())
+ return &kFXCConstantBufferLayoutRulesFamilyImpl;
+
return &kStd140LayoutRulesImpl_;
}
@@ -1307,6 +1329,9 @@ LayoutRulesImpl* GLSLLayoutRulesFamilyImpl::getParameterBlockRules(CompilerOptio
{
if (compilerOptions.shouldUseScalarLayout())
return &kScalarLayoutRulesImpl_;
+ else if (compilerOptions.shouldUseDXLayout())
+ return &kFXCConstantBufferLayoutRulesFamilyImpl;
+
return &kStd140LayoutRulesImpl_;
}
@@ -1324,6 +1349,9 @@ LayoutRulesImpl* GLSLLayoutRulesFamilyImpl::getTextureBufferRules(CompilerOption
{
if (compilerOptions.shouldUseScalarLayout())
return &kScalarLayoutRulesImpl_;
+ else if (compilerOptions.shouldUseDXLayout())
+ return &kFXCConstantBufferLayoutRulesFamilyImpl;
+
return &kStd430LayoutRulesImpl_;
}
@@ -1347,6 +1375,9 @@ LayoutRulesImpl* GLSLLayoutRulesFamilyImpl::getShaderStorageBufferRules(Compiler
{
if (compilerOptions.shouldUseScalarLayout())
return &kScalarLayoutRulesImpl_;
+ else if (compilerOptions.shouldUseDXLayout())
+ return &kFXCShaderResourceLayoutRulesFamilyImpl;
+
return &kStd430LayoutRulesImpl_;
}
@@ -1365,10 +1396,13 @@ LayoutRulesImpl* GLSLLayoutRulesFamilyImpl::getHitAttributesParameterRules()
return &kGLSLHitAttributesParameterLayoutRulesImpl_;
}
-LayoutRulesImpl* GLSLLayoutRulesFamilyImpl::getStructuredBufferRules(CompilerOptionSet& options)
+LayoutRulesImpl* GLSLLayoutRulesFamilyImpl::getStructuredBufferRules(CompilerOptionSet& compilerOptions)
{
- if (options.shouldUseScalarLayout())
+ if (compilerOptions.shouldUseScalarLayout())
return &kScalarLayoutRulesImpl_;
+ else if (compilerOptions.shouldUseDXLayout())
+ return &kFXCShaderResourceLayoutRulesFamilyImpl;
+
return &kGLSLStructuredBufferLayoutRulesImpl_;
}
diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp
index f08a6fc44..3072ef0a7 100644
--- a/source/slang/slang.cpp
+++ b/source/slang/slang.cpp
@@ -5854,6 +5854,11 @@ void EndToEndCompileRequest::setTargetForceGLSLScalarBufferLayout(int targetInde
getTargetOptionSet(targetIndex).set(CompilerOptionName::GLSLForceScalarLayout, value);
}
+void EndToEndCompileRequest::setTargetForceDXLayout(int targetIndex, bool value)
+{
+ getTargetOptionSet(targetIndex).set(CompilerOptionName::ForceDXLayout, value);
+}
+
void EndToEndCompileRequest::setTargetFloatingPointMode(int targetIndex, SlangFloatingPointMode mode)
{
getTargetOptionSet(targetIndex).set(CompilerOptionName::FloatingPointMode, FloatingPointMode(mode));
diff --git a/tests/spirv/cbuffer-dx-layout-1.slang b/tests/spirv/cbuffer-dx-layout-1.slang
new file mode 100644
index 000000000..35d528bda
--- /dev/null
+++ b/tests/spirv/cbuffer-dx-layout-1.slang
@@ -0,0 +1,76 @@
+//TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=CHECK):-vk -compute -xslang -fvk-use-dx-layout -emit-spirv-directly
+//TEST:SIMPLE(filecheck=SPIRV): -target spirv -entry computeMain -stage compute -fvk-use-dx-layout
+//TEST_INPUT:cbuffer(data=[1 2.0 3.0 4.0 5 6 7 0 8 9 10 11 12 0 0 0 13 0 0 0 14 0 0 0 15 0 0 0 16 17 18 0 19 20 21 22 23 24 0 0 25 0 0 0 26 0 0 0]):name=Test
+
+//SPIRV: ArrayStride 16
+
+cbuffer Test
+{
+//SPIRV: Offset 0
+ uint v0;
+//SPIRV: Offset 4
+ float3 v1;
+
+//SPIRV: Offset 16
+ uint3 v2;
+
+//SPIRV: Offset 32
+ uint2 v3;
+//SPIRV: Offset 40
+ uint2 v4;
+
+//SPIRV: Offset 48
+ uint v5[4];
+
+// array always starts on a new register.
+//SPIRV: Offset 112
+ uint3 v6[2];
+//SPIRV: Offset 140
+// non-array can pack with a partially filled register
+ uint v7;
+
+//SPIRV: Offset 144
+ uint2 v8;
+
+// SPIRV: Offset 160
+// array always starts on a new register.
+ uint v9[2];
+};
+
+//TEST_INPUT:ubuffer(data=[0], stride=4):out,name outputBuffer
+RWStructuredBuffer<int> outputBuffer;
+
+__generic<T : IArithmetic, let N : int>
+bool comp(vector<T,N> v1, vector<T,N> v2)
+{
+ for (uint i = 0; i < N; i++)
+ if (v1[i] != v2[i])
+ return false;
+
+ return true;
+}
+
+[shader("compute")]
+[numthreads(2, 2, 1)]
+void computeMain()
+{
+ // CHECK: 64
+
+ outputBuffer[0] = (true
+ && v0 == 1
+ && comp(v1, float3(2, 3, 4))
+ && comp(v2, uint3(5, 6, 7))
+ && comp(v3, uint2(8, 9))
+ && comp(v4, uint2(10, 11))
+ && v5[0] == 12
+ && v5[1] == 13
+ && v5[2] == 14
+ && v5[3] == 15
+ && comp(v6[0], uint3(16, 17, 18))
+ && comp(v6[1], uint3(19, 20, 21))
+ && v7 == 22
+ && comp(v8, uint2(23, 24))
+ && v9[0] == 25
+ && v9[1] == 26
+ ) ? 100 : 0;
+} \ No newline at end of file
diff --git a/tests/spirv/cbuffer-dx-layout-2.slang b/tests/spirv/cbuffer-dx-layout-2.slang
new file mode 100644
index 000000000..19bc6ea9e
--- /dev/null
+++ b/tests/spirv/cbuffer-dx-layout-2.slang
@@ -0,0 +1,86 @@
+//TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=CHECK):-vk -compute -xslang -fvk-use-dx-layout -emit-spirv-directly
+//TEST:SIMPLE(filecheck=SPIRV): -target spirv -entry computeMain -stage compute -fvk-use-dx-layout
+//TEST_INPUT: set Test.v0 = 1;
+//TEST_INPUT: set Test.v1 = {2.0,3.0,4.0};
+//TEST_INPUT: set Test.v2 = {5,6,7};
+//TEST_INPUT: set Test.v3 = {8,9};
+//TEST_INPUT: set Test.v4 = {10,11};
+//TEST_INPUT: set Test.v5 = {12,13,14,15};
+//TEST_INPUT: set Test.v6 = {{16,17,18}, {19,20,21}};
+//TEST_INPUT: set Test.v6 = {{16,17,18}, {19,20,21}};
+//TEST_INPUT: set Test.v7 = 22;
+//TEST_INPUT: set Test.v8 = {23,24};
+//TEST_INPUT: set Test.v9 = {25,26};
+
+//SPIRV_DX: ArrayStride 16
+
+cbuffer Test
+{
+//SPIRV: Offset 0
+ uint v0;
+//SPIRV: Offset 4
+ float3 v1;
+
+//SPIRV: Offset 16
+ uint3 v2;
+
+//SPIRV: Offset 32
+ uint2 v3;
+//SPIRV: Offset 40
+ uint2 v4;
+
+//SPIRV: Offset 48
+ uint v5[4];
+
+//SPIRV: Offset 112
+// Array always starts on a new register.
+ uint3 v6[2];
+//SPIRV: Offset 140
+// Non-array can pack with a partially filled register
+ uint v7;
+
+//SPIRV: Offset 144
+ uint2 v8;
+
+// SPIRV: Offset 160
+// Array always starts on a new register.
+ uint v9[2];
+};
+
+//TEST_INPUT:ubuffer(data=[0], stride=4):out,name outputBuffer
+RWStructuredBuffer<int> outputBuffer;
+
+__generic<T : IArithmetic, let N : int>
+bool comp(vector<T,N> v1, vector<T,N> v2)
+{
+ for (uint i = 0; i < N; i++)
+ if (v1[i] != v2[i])
+ return false;
+
+ return true;
+}
+
+[shader("compute")]
+[numthreads(2, 2, 1)]
+void computeMain()
+{
+ // CHECK: 64
+
+ outputBuffer[0] = (true
+ && v0 == 1
+ && comp(v1, float3(2, 3, 4))
+ && comp(v2, uint3(5, 6, 7))
+ && comp(v3, uint2(8, 9))
+ && comp(v4, uint2(10, 11))
+ && v5[0] == 12
+ && v5[1] == 13
+ && v5[2] == 14
+ && v5[3] == 15
+ && comp(v6[0], uint3(16, 17, 18))
+ && comp(v6[1], uint3(19, 20, 21))
+ && v7 == 22
+ && comp(v8, uint2(23, 24))
+ && v9[0] == 25
+ && v9[1] == 26
+ ) ? 100 : 0;
+} \ No newline at end of file
diff --git a/tests/spirv/cbuffer-dx-layout-3.slang b/tests/spirv/cbuffer-dx-layout-3.slang
new file mode 100644
index 000000000..e05cd25f1
--- /dev/null
+++ b/tests/spirv/cbuffer-dx-layout-3.slang
@@ -0,0 +1,46 @@
+//TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=CHECK):-vk -compute -xslang -fvk-use-dx-layout -emit-spirv-directly
+//TEST:SIMPLE(filecheck=SPIRV): -target spirv -entry computeMain -stage compute -fvk-use-dx-layout
+//TEST_INPUT:cbuffer(data=[1 0 0 0 2.0 3.0 4.0 0 5.0 6.0 7.0 0 8.0 9.0 10.0 11]):name=Test
+
+//SPIRV: ArrayStride 16
+
+cbuffer Test
+{
+//SPIRV: Offset 0
+ uint v0;
+
+//SPIRV: Offset 16
+// matrix always start on a new register
+ float3x3 v1;
+//SPIRV: Offset 60
+// Non-matrix can pack with a partially filled register
+ uint v2;
+};
+
+//TEST_INPUT:ubuffer(data=[0], stride=4):out,name outputBuffer
+RWStructuredBuffer<int> outputBuffer;
+
+__generic<T : IArithmetic, let N : int>
+bool comp(vector<T,N> v1, vector<T,N> v2)
+{
+ for (uint i = 0; i < N; i++)
+ if (v1[i] != v2[i])
+ return false;
+
+ return true;
+}
+
+[shader("compute")]
+[numthreads(2, 2, 1)]
+void computeMain()
+{
+ // CHECK: 64
+
+ outputBuffer[0] = (true
+ && v0 == 1
+ && comp(v1[0], float3(2, 3, 4))
+ && comp(v1[1], float3(5, 6, 7))
+ && comp(v1[2], float3(8, 9, 10))
+ && v2 == 11
+ ) ? 100 : 0;
+} \ No newline at end of file
diff --git a/tests/spirv/cbuffer-dx-layout-4.slang b/tests/spirv/cbuffer-dx-layout-4.slang
new file mode 100644
index 000000000..c7df18e28
--- /dev/null
+++ b/tests/spirv/cbuffer-dx-layout-4.slang
@@ -0,0 +1,52 @@
+// For some reason CI fails this compute test by not loading data correctly
+//IGNORE_TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=CHECK):-vk -compute -xslang -fvk-use-dx-layout
+//TEST:SIMPLE(filecheck=SPIRV): -target spirv -entry computeMain -stage compute -fvk-use-dx-layout
+
+//TEST_INPUT: set Test.v0 = 1;
+//TEST_INPUT: set Test.v1 = {2,3};
+//TEST_INPUT: set Test.v2 = 4;
+
+struct Int_wrapper
+{
+//SPIRV: Offset 0
+ uint v0;
+//SPIRV: Offset 4
+ uint v1;
+};
+
+cbuffer Test
+{
+//SPIRV: Offset 0
+ uint v0;
+
+//SPIRV: Offset 16
+// struct's always start on a new register
+ Int_wrapper v1;
+//SPIRV: Offset 24
+// Non-struct can pack with a partially filled register
+ uint v2;
+};
+
+//TEST_INPUT:ubuffer(data=[0 0 0 0 0], stride=4):out,name outputBuffer
+RWStructuredBuffer<int> outputBuffer;
+
+[shader("compute")]
+[numthreads(2, 2, 1)]
+void computeMain()
+{
+ // CHECK: 64
+
+ outputBuffer[1] = v0;
+ outputBuffer[2] = v1.v0;
+ outputBuffer[3] = v1.v1;
+ outputBuffer[4] = v2;
+
+
+
+ outputBuffer[0] = (true
+ && v0 == 1
+ && v1.v0 == 2
+ && v1.v1 == 3
+ && v2 == 4
+ ) ? 100 : 0;
+} \ No newline at end of file
diff --git a/tests/spirv/cbuffer-not-dx-layout.slang b/tests/spirv/cbuffer-not-dx-layout.slang
new file mode 100644
index 000000000..27063188d
--- /dev/null
+++ b/tests/spirv/cbuffer-not-dx-layout.slang
@@ -0,0 +1,56 @@
+//TEST:SIMPLE(filecheck=SPIRV): -target spirv -entry computeMain -stage compute
+
+cbuffer Test
+{
+//SPIRV: Offset 0
+ uint v0;
+
+//SPIRV: Offset 16
+ float3 v1;
+
+//SPIRV: Offset 32
+ uint3 v2;
+
+//SPIRV: Offset 48
+ uint2 v3;
+
+//SPIRV: Offset 56
+ uint2 v4;
+
+//SPIRV: Offset 64
+ uint v5[4];
+
+//SPIRV: Offset 128
+ uint3 v6[2];
+};
+
+RWStructuredBuffer<int> outputBuffer;
+
+__generic<T : IArithmetic, let N : int>
+bool comp(vector<T,N> v1, vector<T,N> v2)
+{
+ for (uint i = 0; i < N; i++)
+ if (v1[i] != v2[i])
+ return false;
+
+ return true;
+}
+
+[shader("compute")]
+[numthreads(16, 16, 1)]
+void computeMain()
+{
+ outputBuffer[0] = (true
+ && v0 == 1
+ && comp(v1, float3( 2, 3, 4))
+ && comp(v2, uint3( 5, 6, 7))
+ && comp(v3, uint2( 8, 9 ))
+ && comp(v4, uint2( 10, 11 ))
+ && v5[0] == 12
+ && v5[1] == 13
+ && v5[2] == 14
+ && v5[3] == 15
+ && comp(v6[0], uint3( 16, 17, 18 ))
+ && comp(v6[1], uint3( 19, 20, 21 ))
+ ) ? 100 : 0;
+} \ No newline at end of file
diff --git a/tests/spirv/structured-buffer-dx-layout.slang b/tests/spirv/structured-buffer-dx-layout.slang
new file mode 100644
index 000000000..678ad758d
--- /dev/null
+++ b/tests/spirv/structured-buffer-dx-layout.slang
@@ -0,0 +1,57 @@
+//TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=CHECK):-vk -compute -xslang -fvk-use-dx-layout -emit-spirv-directly
+//TEST:SIMPLE(filecheck=SPIRV): -target spirv -entry computeMain -stage compute -fvk-use-dx-layout
+
+struct Test_t
+{
+//SPIRV: Offset 0
+ uint v0;
+//SPIRV: Offset 4
+ float3 v1;
+//SPIRV: Offset 16
+ uint3 v2;
+//SPIRV: Offset 28
+ uint2 v3;
+//SPIRV: Offset 36
+ uint2 v4;
+//SPIRV: Offset 44
+ uint v5[4];
+//SPIRV: Offset 60
+ uint3 v6[2];
+};
+
+//TEST_INPUT:ubuffer(data=[1 2.0 3.0 4.0 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21], stride=4):out,name testBuffer
+RWStructuredBuffer<Test_t> testBuffer;
+
+//TEST_INPUT:ubuffer(data=[0], stride=4):out,name outputBuffer
+RWStructuredBuffer<int> outputBuffer;
+
+__generic<T : IArithmetic, let N : int>
+bool comp(vector<T,N> v1, vector<T,N> v2)
+{
+ for (uint i = 0; i < N; i++)
+ if (v1[i] != v2[i])
+ return false;
+
+ return true;
+}
+
+[shader("compute")]
+[numthreads(16, 16, 1)]
+void computeMain()
+{
+ // CHECK: 64
+ Test_t test = testBuffer[0];
+ outputBuffer[0] = (true
+ && test.v0 == 1
+ && comp(test.v1, float3( 2, 3, 4))
+ && comp(test.v2, uint3( 5, 6, 7))
+ && comp(test.v3, uint2( 8, 9 ))
+ && comp(test.v4, uint2( 10, 11 ))
+ && test.v5[0] == 12
+ && test.v5[1] == 13
+ && test.v5[2] == 14
+ && test.v5[3] == 15
+ && comp(test.v6[0], uint3( 16, 17, 18 ))
+ && comp(test.v6[1], uint3( 19, 20, 21 ))
+ ) ? 100 : 0;
+} \ No newline at end of file
diff --git a/tests/spirv/tbuffer-dx-layout-1.slang b/tests/spirv/tbuffer-dx-layout-1.slang
new file mode 100644
index 000000000..c1f494497
--- /dev/null
+++ b/tests/spirv/tbuffer-dx-layout-1.slang
@@ -0,0 +1,73 @@
+//IGNORE_TEST:SIMPLE(filecheck=SPIRV): -target spirv -entry computeMain -stage compute -fvk-use-dx-layout
+
+// 'tbuffer' is not implemented for SPIRV targets currently.
+
+tbuffer Test
+{
+//SPIRV: Offset 0
+ uint v0;
+//SPIRV: Offset 4
+ float3 v1;
+
+//SPIRV: Offset 16
+ uint3 v2;
+
+//SPIRV: Offset 32
+ uint2 v3;
+//SPIRV: Offset 40
+ uint2 v4;
+
+//SPIRV: Offset 48
+ uint v5[4];
+
+// array always starts on a new register.
+//SPIRV: Offset 112
+ uint3 v6[2];
+//SPIRV: Offset 140
+// non-array can pack with a partially filled register
+ uint v7;
+
+//SPIRV: Offset 144
+ uint2 v8;
+
+// SPIRV: Offset 160
+// array always starts on a new register.
+ uint v9[2];
+};
+
+RWStructuredBuffer<int> outputBuffer;
+
+__generic<T : IArithmetic, let N : int>
+bool comp(vector<T,N> v1, vector<T,N> v2)
+{
+ for (uint i = 0; i < N; i++)
+ if (v1[i] != v2[i])
+ return false;
+
+ return true;
+}
+
+[shader("compute")]
+[numthreads(2, 2, 1)]
+void computeMain()
+{
+ // CHECK: 64
+
+ outputBuffer[0] = (true
+ && v0 == 1
+ && comp(v1, float3(2, 3, 4))
+ && comp(v2, uint3(5, 6, 7))
+ && comp(v3, uint2(8, 9))
+ && comp(v4, uint2(10, 11))
+ && v5[0] == 12
+ && v5[1] == 13
+ && v5[2] == 14
+ && v5[3] == 15
+ && comp(v6[0], uint3(16, 17, 18))
+ && comp(v6[1], uint3(19, 20, 21))
+ && v7 == 22
+ && comp(v8, uint2(23, 24))
+ && v9[0] == 25
+ && v9[1] == 26
+ ) ? 100 : 0;
+} \ No newline at end of file