summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/user-guide/a2-04-glsl-target-specific.md90
-rw-r--r--docs/user-guide/a2-target-specific-features.md1
-rw-r--r--docs/user-guide/toc.html15
-rw-r--r--source/slang/slang-ir-layout.cpp113
-rw-r--r--source/slang/slang-ir-layout.h14
-rw-r--r--tests/expected-failure.txt2
-rw-r--r--tests/hlsl/cbuffer-float3-offsets-aligned.slang115
-rw-r--r--tests/hlsl/cbuffer-float3-offsets-unaligned.slang138
8 files changed, 447 insertions, 41 deletions
diff --git a/docs/user-guide/a2-04-glsl-target-specific.md b/docs/user-guide/a2-04-glsl-target-specific.md
new file mode 100644
index 000000000..2a36c3d90
--- /dev/null
+++ b/docs/user-guide/a2-04-glsl-target-specific.md
@@ -0,0 +1,90 @@
+---
+layout: user-guide
+permalink: /user-guide/glsl-target-specific
+---
+
+# GLSL-Specific Functionalities
+
+This page documents features and behaviors unique to the GLSL target in Slang. For any features or translation rules that are identical to the SPIR-V target, see the [SPIR-V Target Specific](./a2-01-spirv-target-specific.md) page.
+
+> **Note:** The GLSL target in Slang is currently less mature than the SPIR-V target and has several known limitations. While basic functionality works, some advanced features may not be fully supported or may behave differently than expected. Due to fundamental limitations of GLSL, the GLSL target is not expected to achieve feature parity with other backends. For cross-platform use cases, we recommend using the SPIR-V target for more complete and reliable shader compilation. This document is a work in progress and will be updated as the GLSL target matures and more limitations are documented.
+
+## Combined Texture Sampler
+
+Combined texture samplers (e.g., `Sampler2D`) are mapped directly to GLSL sampler types. See SPIR-V page for details on explicit bindings and emulation on other targets.
+
+## System-Value Semantics
+
+System-value semantics are mapped to the corresponding GLSL built-in variables (e.g., `gl_Position`, `gl_FragCoord`, etc.). For a full mapping table, refer to the [SPIR-V Target Specific](./a2-01-spirv-target-specific.md) page.
+
+## `discard` Statement
+
+The `discard` statement in Slang maps directly to GLSL's `discard` keyword, which exits the current fragment shader invocation. No special handling is required.
+
+## HLSL Features Supported in GLSL
+
+Slang supports many HLSL features when targeting GLSL, including:
+- Geometry shaders
+- Tessellation shaders
+- Compute shaders
+- Atomics (see below for type support)
+- Wave intrinsics (where supported by GLSL extensions)
+
+## Atomic Types
+
+GLSL supports atomic operations on:
+- 32-bit integer types (GLSL 4.3+)
+- 64-bit integer types (GLSL 4.4+ with `GL_EXT_shader_atomic_int64`)
+- 32-bit float types (GLSL 4.6+ with `GLSL_EXT_shader_atomic_float`)
+- 16-bit float types (GLSL 4.6+ with `GLSL_EXT_shader_atomic_float2`)
+See the SPIR-V page for a comparative table.
+
+## Buffer Types
+
+- `ConstantBuffer` members are emitted as `uniform` parameters in a uniform block.
+- `StructuredBuffer` and `ByteAddressBuffer` are translated to shader storage buffers (`buffer` in GLSL 4.3+).
+- Layouts can be controlled with `std140`, `std430`, or `scalar` layouts (see options below).
+
+## Matrix Layout
+
+GLSL uses column-major layout by default. Slang will handle row-major to column-major translation as needed. For more on matrix layout and memory layout, see the [SPIR-V Target Specific](./a2-01-spirv-target-specific.md) and [Matrix Layout](./a1-01-matrix-layout.md) pages.
+
+## Entry Points
+
+GLSL requires the entry point to be named `main`. Only one entry point per shader is supported. For multiple entry points or advanced scenarios, see the SPIR-V page.
+
+## Specialization Constants
+
+Slang supports specialization constants in GLSL using the `layout(constant_id = N)` syntax or the `[SpecializationConstant]` attribute. See the SPIR-V page for details.
+
+## Attributes and Layout Qualifiers
+
+Slang attributes such as `[[vk::location]]`, `[[vk::binding]]`, etc., are mapped to GLSL `layout` qualifiers where possible.
+
+## GLSL-Specific Compiler Options
+
+Relevant options for GLSL output:
+
+### -profile glsl_<version>
+Select the GLSL version to target (e.g., `-profile glsl_450`).
+
+### -force-glsl-scalar-layout
+Use scalar layout for buffer types.
+
+> **Note:** Scalar layout is generally only supported by Vulkan consumers of GLSL, and is not expected to be usable for OpenGL.
+
+### -fvk-use-dx-layout
+Use D3D buffer layout rules.
+
+### -fvk-use-gl-layout
+Use std430 layout for raw buffer load/stores.
+
+### -line-directive-mode glsl
+Emit GLSL-style `#line` directives.
+
+### -default-downstream-compiler glsl <compiler>
+Set the downstream GLSL compiler (e.g., glslang).
+
+> **Note:** The GLSL target has a known limitation with constant buffer packing for 3-element vectors, where it cannot always reproduce the same exact buffer layout. For example, when a 3-element vector follows a scalar in a constant buffer, the alignment differs from a 4-element vector, causing incorrect packing.
+
+For all other behaviors, translation rules, and advanced features, refer to the [SPIR-V Target Specific](./a2-01-spirv-target-specific.md) page.
diff --git a/docs/user-guide/a2-target-specific-features.md b/docs/user-guide/a2-target-specific-features.md
index 495148c49..7949a00db 100644
--- a/docs/user-guide/a2-target-specific-features.md
+++ b/docs/user-guide/a2-target-specific-features.md
@@ -11,6 +11,7 @@ In this chapter:
1. [SPIR-V target specific](./a2-01-spirv-target-specific.md)
2. [Metal target specific](./a2-02-metal-target-specific.md)
3. [WGSL target specific](./a2-03-wgsl-target-specific.md)
+4. [GLSL target specific](./a2-04-glsl-target-specific.md)
<!-- RTD-TOC-START
```{toctree}
diff --git a/docs/user-guide/toc.html b/docs/user-guide/toc.html
index 1621d1da5..f559fec31 100644
--- a/docs/user-guide/toc.html
+++ b/docs/user-guide/toc.html
@@ -260,6 +260,21 @@
<li data-link="wgsl-target-specific#specialization-constants"><span>Specialization Constants</span></li>
</ul>
</li>
+<li data-link="glsl-target-specific"><span>GLSL-Specific Functionalities</span>
+<ul class="toc_list">
+<li data-link="glsl-target-specific#combined-texture-sampler"><span>Combined Texture Sampler</span></li>
+<li data-link="glsl-target-specific#system-value-semantics"><span>System-Value Semantics</span></li>
+<li data-link="glsl-target-specific#discard-statement"><span>`discard` Statement</span></li>
+<li data-link="glsl-target-specific#hlsl-features-supported-in-glsl"><span>HLSL Features Supported in GLSL</span></li>
+<li data-link="glsl-target-specific#atomic-types"><span>Atomic Types</span></li>
+<li data-link="glsl-target-specific#buffer-types"><span>Buffer Types</span></li>
+<li data-link="glsl-target-specific#matrix-layout"><span>Matrix Layout</span></li>
+<li data-link="glsl-target-specific#entry-points"><span>Entry Points</span></li>
+<li data-link="glsl-target-specific#specialization-constants"><span>Specialization Constants</span></li>
+<li data-link="glsl-target-specific#attributes-and-layout-qualifiers"><span>Attributes and Layout Qualifiers</span></li>
+<li data-link="glsl-target-specific#glsl-specific-compiler-options"><span>GLSL-Specific Compiler Options</span></li>
+</ul>
+</li>
</ul>
</li>
<li data-link="reference"><span>Reference</span>
diff --git a/source/slang/slang-ir-layout.cpp b/source/slang/slang-ir-layout.cpp
index 7b3aa4340..795f47f55 100644
--- a/source/slang/slang-ir-layout.cpp
+++ b/source/slang/slang-ir-layout.cpp
@@ -151,6 +151,8 @@ static Result _calcSizeAndAlignment(
auto structType = cast<IRStructType>(type);
IRSizeAndAlignment structLayout;
IRIntegerValue offset = 0;
+ IRIntegerValue lastFieldAlignment = 0;
+ IRType* lastFieldType = NULL;
bool seenFinalUnsizedArrayField = false;
for (auto field : structType->getFields())
{
@@ -159,18 +161,26 @@ static Result _calcSizeAndAlignment(
// subsequent offsets
SLANG_ASSERT(!seenFinalUnsizedArrayField);
- if (auto offsetDecor =
- field->getKey()->findDecoration<IRVkStructOffsetDecoration>())
- {
- offset = offsetDecor->getOffset()->getValue();
- }
-
IRSizeAndAlignment fieldTypeLayout;
SLANG_RETURN_ON_FAIL(
getSizeAndAlignment(optionSet, rules, field->getFieldType(), &fieldTypeLayout));
seenFinalUnsizedArrayField =
fieldTypeLayout.size == IRSizeAndAlignment::kIndeterminateSize;
+ if (auto offsetDecor =
+ field->getKey()->findDecoration<IRVkStructOffsetDecoration>())
+ {
+ offset = offsetDecor->getOffset()->getValue();
+ }
+ else
+ {
+ offset = rules->adjustOffset(
+ offset,
+ fieldTypeLayout.size,
+ lastFieldType,
+ lastFieldAlignment);
+ }
+
structLayout.size = align(offset, fieldTypeLayout.alignment);
structLayout.alignment =
std::max(structLayout.alignment, fieldTypeLayout.alignment);
@@ -195,14 +205,8 @@ static Result _calcSizeAndAlignment(
if (!seenFinalUnsizedArrayField)
structLayout.size += fieldTypeLayout.size;
offset = structLayout.size;
- if (as<IRMatrixType>(field->getFieldType()) ||
- as<IRArrayTypeBase>(field->getFieldType()) ||
- as<IRStructType>(field->getFieldType()))
- {
- offset = rules->adjustOffsetForNextAggregateMember(
- offset,
- fieldTypeLayout.alignment);
- }
+ lastFieldType = field->getFieldType();
+ lastFieldAlignment = fieldTypeLayout.alignment;
}
*outSizeAndAlignment = rules->alignCompositeElement(structLayout);
return SLANG_OK;
@@ -498,17 +502,23 @@ Result getOffset(
struct NaturalLayoutRules : IRTypeLayoutRules
{
NaturalLayoutRules() { ruleName = IRTypeLayoutRuleName::Natural; }
- virtual IRIntegerValue adjustOffsetForNextAggregateMember(
- IRIntegerValue currentSize,
- IRIntegerValue lastElementAlignment)
+ virtual IRIntegerValue adjustOffset(
+ IRIntegerValue offset,
+ IRIntegerValue elementSize,
+ IRType* lastFieldType,
+ IRIntegerValue lastFieldAlignment)
{
- SLANG_UNUSED(lastElementAlignment);
- return currentSize;
+ SLANG_UNUSED(elementSize);
+ SLANG_UNUSED(lastFieldType);
+ SLANG_UNUSED(lastFieldAlignment);
+ return offset;
}
+
virtual IRSizeAndAlignment alignCompositeElement(IRSizeAndAlignment elementSize)
{
return elementSize;
}
+
virtual IRSizeAndAlignment getVectorSizeAndAlignment(
IRSizeAndAlignment element,
IRIntegerValue count)
@@ -528,22 +538,30 @@ struct ConstantBufferLayoutRules : IRTypeLayoutRules
return IRSizeAndAlignment(currentSize.size, 16);
}
- virtual IRIntegerValue adjustOffsetForNextAggregateMember(
- IRIntegerValue currentSize,
- IRIntegerValue lastElementAlignment)
+ virtual IRIntegerValue adjustOffset(
+ IRIntegerValue offset,
+ IRIntegerValue elementSize,
+ IRType* lastFieldType,
+ IRIntegerValue lastFieldAlignment)
{
- SLANG_UNUSED(lastElementAlignment);
- return currentSize;
+ SLANG_UNUSED(lastFieldType);
+ SLANG_UNUSED(lastFieldAlignment);
+
+ // If the element would cross a 16-byte boundary, align to the next boundary
+ auto currentChunk = offset / 16;
+ auto endChunk = (offset + elementSize - 1) / 16;
+ if (currentChunk != endChunk)
+ {
+ return align(offset, 16);
+ }
+ return offset;
}
virtual IRSizeAndAlignment getVectorSizeAndAlignment(
IRSizeAndAlignment element,
IRIntegerValue count)
{
- IRIntegerValue countForAlignment = count;
- return IRSizeAndAlignment(
- (int)(element.size * count),
- (int)(element.size * countForAlignment));
+ return IRSizeAndAlignment(element.size * count, element.alignment);
}
};
@@ -551,15 +569,24 @@ struct Std430LayoutRules : IRTypeLayoutRules
{
Std430LayoutRules() { ruleName = IRTypeLayoutRuleName::Std430; }
- virtual IRSizeAndAlignment alignCompositeElement(IRSizeAndAlignment elementSize)
+ virtual IRIntegerValue adjustOffset(
+ IRIntegerValue offset,
+ IRIntegerValue elementSize,
+ IRType* lastFieldType,
+ IRIntegerValue lastFieldAlignment)
{
- return elementSize;
+ SLANG_UNUSED(elementSize);
+ if (as<IRMatrixType>(lastFieldType) || as<IRArrayTypeBase>(lastFieldType) ||
+ as<IRStructType>(lastFieldType))
+ {
+ return align(offset, (int)lastFieldAlignment);
+ }
+ return offset;
}
- virtual IRIntegerValue adjustOffsetForNextAggregateMember(
- IRIntegerValue currentSize,
- IRIntegerValue lastElementAlignment)
+
+ virtual IRSizeAndAlignment alignCompositeElement(IRSizeAndAlignment elementSize)
{
- return align(currentSize, (int)lastElementAlignment);
+ return elementSize;
}
virtual IRSizeAndAlignment getVectorSizeAndAlignment(
@@ -579,18 +606,28 @@ struct Std140LayoutRules : IRTypeLayoutRules
{
Std140LayoutRules() { ruleName = IRTypeLayoutRuleName::Std140; }
- virtual IRIntegerValue adjustOffsetForNextAggregateMember(
- IRIntegerValue currentSize,
- IRIntegerValue lastElementAlignment)
+ virtual IRIntegerValue adjustOffset(
+ IRIntegerValue offset,
+ IRIntegerValue elementSize,
+ IRType* lastFieldType,
+ IRIntegerValue lastFieldAlignment)
{
- return align(currentSize, (int)lastElementAlignment);
+ SLANG_UNUSED(elementSize);
+ if (as<IRMatrixType>(lastFieldType) || as<IRArrayTypeBase>(lastFieldType) ||
+ as<IRStructType>(lastFieldType))
+ {
+ return align(offset, (int)lastFieldAlignment);
+ }
+ return offset;
}
+
virtual IRSizeAndAlignment alignCompositeElement(IRSizeAndAlignment elementSize)
{
elementSize.alignment = (int)align(elementSize.alignment, 16);
elementSize.size = align(elementSize.size, elementSize.alignment);
return elementSize;
}
+
virtual IRSizeAndAlignment getVectorSizeAndAlignment(
IRSizeAndAlignment element,
IRIntegerValue count)
diff --git a/source/slang/slang-ir-layout.h b/source/slang/slang-ir-layout.h
index db115a936..1918f31b6 100644
--- a/source/slang/slang-ir-layout.h
+++ b/source/slang/slang-ir-layout.h
@@ -65,9 +65,17 @@ public:
virtual IRSizeAndAlignment getVectorSizeAndAlignment(
IRSizeAndAlignment element,
IRIntegerValue count) = 0;
- virtual IRIntegerValue adjustOffsetForNextAggregateMember(
- IRIntegerValue currentSize,
- IRIntegerValue lastElementAlignment) = 0;
+
+ /// Adjust the offset of an element. Handles two cases; alignmment when
+ /// the previous field was a composite, and the D3D constant buffer case
+ /// where an element is aligned to the next 16-byte boundary if it doesn't
+ /// fit entirely within the current one.
+ virtual IRIntegerValue adjustOffset(
+ IRIntegerValue offset,
+ IRIntegerValue elementSize,
+ IRType* lastFieldType,
+ IRIntegerValue lastFieldAlignment) = 0;
+
static IRTypeLayoutRules* getStd430();
static IRTypeLayoutRules* getStd140();
static IRTypeLayoutRules* getNatural();
diff --git a/tests/expected-failure.txt b/tests/expected-failure.txt
index 7283c8d97..22142e31d 100644
--- a/tests/expected-failure.txt
+++ b/tests/expected-failure.txt
@@ -5,3 +5,5 @@ tests/language-feature/saturated-cooperation/fuse.slang (vk)
tests/bugs/byte-address-buffer-interlocked-add-f32.slang (vk)
tests/ir/loop-unroll-0.slang.1 (vk)
tests/hlsl-intrinsic/texture/float-atomics.slang (vk)
+tests/hlsl/cbuffer-float3-offsets-aligned.slang.2 (vk)
+tests/hlsl/cbuffer-float3-offsets-unaligned.slang.2 (vk)
diff --git a/tests/hlsl/cbuffer-float3-offsets-aligned.slang b/tests/hlsl/cbuffer-float3-offsets-aligned.slang
new file mode 100644
index 000000000..7c548546a
--- /dev/null
+++ b/tests/hlsl/cbuffer-float3-offsets-aligned.slang
@@ -0,0 +1,115 @@
+//TEST:SIMPLE(filecheck=SPIRV): -target spirv -profile cs_6_2 -entry computeMain -line-directive-mode none -fvk-use-dx-layout
+//TEST(compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUFFER):-slang -compute -dx12 -use-dxil -profile cs_6_2 -Xslang... -Xdxc -fvk-use-dx-layout -Xdxc -enable-16bit-types -X. -output-using-type
+//TEST(compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUFFER):-slang -compute -vk -profile cs_6_2 -Xslang... -fvk-use-dx-layout -X. -output-using-type
+//TEST:REFLECTION(filecheck=REFLECT):-stage compute -entry computeMain -target spirv -profile cs_6_2 -no-codegen -line-directive-mode none -fvk-use-dx-layout
+
+//TEST_INPUT:ubuffer(stride=4, count=17):out,name=outputBuffer
+RWStructuredBuffer<float> outputBuffer;
+
+//TEST_INPUT:set Constants.v0={1.0,2.0,3.0}
+//TEST_INPUT:set Constants.v1=4.0
+//TEST_INPUT:set Constants.v2=5.0
+//TEST_INPUT:set Constants.v3[0]={6.0,7.0,8.0}
+//TEST_INPUT:set Constants.v3[1]={9.0,10.0,11.0}
+//TEST_INPUT:set Constants.v4=12.0
+//TEST_INPUT:set Constants.v5=13.0
+//TEST_INPUT:set Constants.v6[0]={14.0,15.0,16.0}
+//TEST_INPUT:set Constants.v7=17.0
+
+// Checks cbuffer packing rule cases involving 3-element vectors.
+// HLSL aligns at the element size, while GLSL std140 and std430
+// align to the size of a 4-element vector of the element type.
+// Checks cases that are compatible with std140 and std430.
+
+cbuffer Constants
+{
+ // float v1 should be packed in with float3 v0
+ float3 v0;
+ float v1;
+
+ // float3[2] v3 should be aligned to next 16 byte boundary,
+ // and not packed in with float v2.
+ float v2;
+ float3 v3[2];
+
+ // float v4 should be packed in with last float3 from v3.
+ float v4;
+
+ // float3[1] v6 should be aligned to next 16 byte boundary
+ // and not packed in with float v5.
+ float v5;
+ float3 v6[1];
+
+ // float v7 should be packed in with float3 from v6.
+ float v7;
+};
+
+// For spirv, check that the offsets are correct.
+// SPIRV: OpMemberDecorate {{.*}} 0 Offset 0
+// SPIRV: OpMemberDecorate {{.*}} 1 Offset 12
+// SPIRV: OpMemberDecorate {{.*}} 2 Offset 16
+// SPIRV: OpMemberDecorate {{.*}} 3 Offset 32
+// SPIRV: OpMemberDecorate {{.*}} 4 Offset 60
+// SPIRV: OpMemberDecorate {{.*}} 5 Offset 64
+// SPIRV: OpMemberDecorate {{.*}} 6 Offset 80
+// SPIRV: OpMemberDecorate {{.*}} 7 Offset 92
+
+// REFLECT: "name": "v0",
+// REFLECT: "offset": 0
+// REFLECT: "name": "v1",
+// REFLECT: "offset": 12
+// REFLECT: "name": "v2",
+// REFLECT: "offset": 16
+// REFLECT: "name": "v3",
+// REFLECT: "offset": 32
+// REFLECT: "name": "v4",
+// REFLECT: "offset": 60
+// REFLECT: "name": "v5",
+// REFLECT: "offset": 64
+// REFLECT: "name": "v6",
+// REFLECT: "offset": 80
+// REFLECT: "name": "v7",
+// REFLECT: "offset": 92
+
+[numthreads(1, 1, 1)]
+void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
+{
+ int i = 0;
+ outputBuffer[i++] = v0.x;
+ outputBuffer[i++] = v0.y;
+ outputBuffer[i++] = v0.z;
+ outputBuffer[i++] = v1;
+ outputBuffer[i++] = v2;
+ outputBuffer[i++] = v3[0].x;
+ outputBuffer[i++] = v3[0].y;
+ outputBuffer[i++] = v3[0].z;
+ outputBuffer[i++] = v3[1].x;
+ outputBuffer[i++] = v3[1].y;
+ outputBuffer[i++] = v3[1].z;
+ outputBuffer[i++] = v4;
+ outputBuffer[i++] = v5;
+ outputBuffer[i++] = v6[0].x;
+ outputBuffer[i++] = v6[0].y;
+ outputBuffer[i++] = v6[0].z;
+ outputBuffer[i++] = v7;
+
+ // BUFFER: 1
+ // BUFFER-NEXT: 2
+ // BUFFER-NEXT: 3
+ // BUFFER-NEXT: 4
+ // BUFFER-NEXT: 5
+ // BUFFER-NEXT: 6
+ // BUFFER-NEXT: 7
+ // BUFFER-NEXT: 8
+ // BUFFER-NEXT: 9
+ // BUFFER-NEXT: 10
+ // BUFFER-NEXT: 11
+ // BUFFER-NEXT: 12
+ // BUFFER-NEXT: 13
+ // BUFFER-NEXT: 14
+ // BUFFER-NEXT: 15
+ // BUFFER-NEXT: 16
+ // BUFFER-NEXT: 17
+
+}
+
diff --git a/tests/hlsl/cbuffer-float3-offsets-unaligned.slang b/tests/hlsl/cbuffer-float3-offsets-unaligned.slang
new file mode 100644
index 000000000..c3824d1a2
--- /dev/null
+++ b/tests/hlsl/cbuffer-float3-offsets-unaligned.slang
@@ -0,0 +1,138 @@
+//TEST:SIMPLE(filecheck=SPIRV): -target spirv -profile cs_6_2 -entry computeMain -line-directive-mode none -fvk-use-dx-layout
+//TEST(compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUFFER):-slang -compute -dx12 -use-dxil -Xslang... -Xdxc -fvk-use-dx-layout -Xdxc -enable-16bit-types -X. -output-using-type
+//TEST(compute):COMPARE_COMPUTE_EX(filecheck-buffer=BUFFER):-slang -compute -vk -Xslang... -fvk-use-dx-layout -X. -output-using-type
+//TEST:REFLECTION(filecheck=REFLECT):-stage compute -entry computeMain -target spirv -profile cs_6_2 -no-codegen -line-directive-mode none -fvk-use-dx-layout
+
+// dxc: -T cs_6_2 -E computeMain -spirv -fvk-use-dx-layout -enable-16bit-types
+
+//TEST_INPUT:ubuffer(stride=4, count=24):out,name=outputBuffer
+RWStructuredBuffer<float> outputBuffer;
+
+//TEST_INPUT:set Constants.v0=1.0
+//TEST_INPUT:set Constants.v1={2.0,3.0,4.0}
+//TEST_INPUT:set Constants.v2=0x4500
+//TEST_INPUT:set Constants.v3={0x4600,0x4700,0x4800}
+//TEST_INPUT:set Constants.v4=0x4880
+//TEST_INPUT:set Constants.v5={0x4900,0x4980,0x4a00}
+//TEST_INPUT:set Constants.v6=0x4a80
+//TEST_INPUT:set Constants.v7={0x4b00,0x4b80,0x4c00,0x4c40}
+//TEST_INPUT:set Constants.v8={0x4c80,0x4cc0,0x4d00}
+//TEST_INPUT:set Constants.v9=0x4d40
+//TEST_INPUT:set Constants.v10={22.0,23.0,24.0}
+
+
+// Checks cbuffer packing rule cases involving 3-element vectors.
+// HLSL aligns at the element size, while GLSL std140 and std430
+// align to the size of a 4-element vector of the element type.
+// Checks cases that are not compatible with std140 and std430.
+
+cbuffer Constants
+{
+ // float3 v1 should be packed in with float v0.
+ float v0;
+ float3 v1;
+
+ // v2,v3,v4,v5 should all be packed together
+ float16_t v2;
+ vector<float16_t, 3> v3;
+ float16_t v4;
+ vector<float16_t, 3> v5;
+
+ float16_t v6;
+ vector<float16_t, 4> v7;
+ vector<float16_t, 3> v8;
+
+ // There should be a 2-byte gap between v4 and v5.
+ float16_t v9;
+ float3 v10;
+};
+
+// SPIRV: OpMemberDecorate {{.*}} 0 Offset 0
+// SPIRV: OpMemberDecorate {{.*}} 1 Offset 4
+// SPIRV: OpMemberDecorate {{.*}} 2 Offset 16
+// SPIRV: OpMemberDecorate {{.*}} 3 Offset 18
+// SPIRV: OpMemberDecorate {{.*}} 4 Offset 24
+// SPIRV: OpMemberDecorate {{.*}} 5 Offset 26
+// SPIRV: OpMemberDecorate {{.*}} 6 Offset 32
+// SPIRV: OpMemberDecorate {{.*}} 7 Offset 34
+// SPIRV: OpMemberDecorate {{.*}} 8 Offset 42
+// SPIRV: OpMemberDecorate {{.*}} 9 Offset 48
+// SPIRV: OpMemberDecorate {{.*}} 10 Offset 52
+
+// REFLECT: "name": "v0",
+// REFLECT: "offset": 0
+// REFLECT: "name": "v1",
+// REFLECT: "offset": 4
+// REFLECT: "name": "v2",
+// REFLECT: "offset": 16
+// REFLECT: "name": "v3",
+// REFLECT: "offset": 18
+// REFLECT: "name": "v4",
+// REFLECT: "offset": 24
+// REFLECT: "name": "v5",
+// REFLECT: "offset": 26
+// REFLECT: "name": "v6",
+// REFLECT: "offset": 32
+// REFLECT: "name": "v7",
+// REFLECT: "offset": 34
+// REFLECT: "name": "v8",
+// REFLECT: "offset": 42
+// REFLECT: "name": "v9",
+// REFLECT: "offset": 48
+// REFLECT: "name": "v10",
+// REFLECT: "offset": 52
+
+[numthreads(1, 1, 1)]
+void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
+{
+ int i = 0;
+ outputBuffer[i++] = v0;
+ outputBuffer[i++] = v1.x;
+ outputBuffer[i++] = v1.y;
+ outputBuffer[i++] = v1.z;
+ outputBuffer[i++] = v2;
+ outputBuffer[i++] = v3.x;
+ outputBuffer[i++] = v3.y;
+ outputBuffer[i++] = v3.z;
+ outputBuffer[i++] = v4;
+ outputBuffer[i++] = v5.x;
+ outputBuffer[i++] = v5.y;
+ outputBuffer[i++] = v5.z;
+ outputBuffer[i++] = v6;
+ outputBuffer[i++] = v7.x;
+ outputBuffer[i++] = v7.y;
+ outputBuffer[i++] = v7.z;
+ outputBuffer[i++] = v7.w;
+ outputBuffer[i++] = v8.x;
+ outputBuffer[i++] = v8.y;
+ outputBuffer[i++] = v8.z;
+ outputBuffer[i++] = v9;
+ outputBuffer[i++] = v10.x;
+ outputBuffer[i++] = v10.y;
+ outputBuffer[i++] = v10.z;
+
+ // BUFFER: 1
+ // BUFFER-NEXT: 2
+ // BUFFER-NEXT: 3
+ // BUFFER-NEXT: 4
+ // BUFFER-NEXT: 5
+ // BUFFER-NEXT: 6
+ // BUFFER-NEXT: 7
+ // BUFFER-NEXT: 8
+ // BUFFER-NEXT: 9
+ // BUFFER-NEXT: 10
+ // BUFFER-NEXT: 11
+ // BUFFER-NEXT: 12
+ // BUFFER-NEXT: 13
+ // BUFFER-NEXT: 14
+ // BUFFER-NEXT: 15
+ // BUFFER-NEXT: 16
+ // BUFFER-NEXT: 17
+ // BUFFER-NEXT: 18
+ // BUFFER-NEXT: 19
+ // BUFFER-NEXT: 20
+ // BUFFER-NEXT: 21
+ // BUFFER-NEXT: 22
+ // BUFFER-NEXT: 23
+ // BUFFER-NEXT: 24
+}