Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
81f9636
Better handling for 16-byte boundary of d3d cbuffer
jhelferty-nv May 26, 2025
bfe3893
Add scalar layout checks for constant buffers in GLSL emitter
jhelferty-nv May 29, 2025
f782250
Enhance struct declaration handling with forceScalarOffsets parameter
jhelferty-nv May 29, 2025
e4e1a0e
Clean up test cases for float3
jhelferty-nv May 30, 2025
31cf97c
Merge branch 'shader-slang:master' into feature/cbuffer-wrap-fix
jhelferty-nv May 30, 2025
82e7ea3
Merge branch 'shader-slang:master' into feature/cbuffer-wrap-fix
jhelferty-nv Jun 2, 2025
72c531b
Revise adjustOffset logic
jhelferty-nv Jun 1, 2025
17cc9f4
Take into account pack offset declarations
jhelferty-nv Jun 3, 2025
fb397e4
Revert changes for GLSL target support
jhelferty-nv Jun 4, 2025
c62aedf
Add GLSL target documentation
jhelferty-nv Jun 4, 2025
435cef3
Rename tests
jhelferty-nv Jun 4, 2025
77ff4a6
Adds compute tests to test cases, minor cleanups
jhelferty-nv Jun 4, 2025
8077a94
Update packoffset test
jhelferty-nv Jun 4, 2025
aea2435
Remove packoffset from tests, add reflection
jhelferty-nv Jun 5, 2025
7ea6e3f
Revert "Update packoffset test"
jhelferty-nv Jun 5, 2025
caeb217
Revert packoffset use in IR layout calculation
jhelferty-nv Jun 5, 2025
00701cb
Update documentation
jhelferty-nv Jun 5, 2025
039b932
Merge branch 'shader-slang:master' into feature/cbuffer-wrap-fix
jhelferty-nv Jun 5, 2025
57e8a2c
Fix formatting
jhelferty-nv Jun 5, 2025
f757149
docs: Update toc
jhelferty-nv Jun 5, 2025
42e4171
Mark new tests as expected failures for VK via GLSL
jhelferty-nv Jun 6, 2025
c6fb662
Merge branch 'master' into feature/cbuffer-wrap-fix
jhelferty-nv Jun 6, 2025
ca0ee09
Merge branch 'master' into feature/cbuffer-wrap-fix
jhelferty-nv Jun 9, 2025
edc77ff
Remove assert
jhelferty-nv Jun 10, 2025
42e2671
Merge branch 'master' into feature/cbuffer-wrap-fix
jhelferty-nv Jun 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions docs/user-guide/a2-04-glsl-target-specific.md
Original file line number Diff line number Diff line change
@@ -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.
1 change: 1 addition & 0 deletions docs/user-guide/a2-target-specific-features.md
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
15 changes: 15 additions & 0 deletions docs/user-guide/toc.html
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
113 changes: 75 additions & 38 deletions source/slang/slang-ir-layout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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())
{
Expand All @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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)
Expand All @@ -528,38 +538,55 @@ 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);
}
};

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) ||
Comment thread
kaizhangNV marked this conversation as resolved.
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(
Expand All @@ -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)
Expand Down
14 changes: 11 additions & 3 deletions source/slang/slang-ir-layout.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,17 @@ struct IRTypeLayoutRules
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();
Expand Down
2 changes: 2 additions & 0 deletions tests/expected-failure.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we add a test that is expected to fail? Any plan to fix this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These succeed on Vulkan using the SPIRV target, but do not succeed on Vulkan using the GLSL target. Kai told me to add the tests here to disable error reporting for Vulkan with GLSL target. It sounds like that's not correct; will fix.

tests/hlsl/cbuffer-float3-offsets-unaligned.slang.2 (vk)
Loading
Loading