• Slang User's Guide
    • Introduction
      • Why use Slang?
      • Who is Slang for?
      • Who is this guide for?
      • Goals and Non-Goals
    • Getting Started with Slang
      • Installation
      • Your first Slang shader
      • The full example
    • Conventional Language Features
      • Types
      • Expressions
      • Statements
      • Functions
      • Preprocessor
      • Attributes
      • Global Variables and Shader Parameters
      • Shader Entry Points
      • Mixed Shader Entry Points
      • Auto-Generated Constructors
      • Initializer Lists
    • Basic Convenience Features
      • Type Inference in Variable Definitions
      • Immutable Values
      • Namespaces
      • Member functions
      • Properties
      • Initializers
      • Operator Overloading
      • Subscript Operator
      • Tuple Types
      • `Optional<T>` type
      • `Conditional<T, bool condition>` Type
      • `if_let` syntax
      • `reinterpret<T>` operation
      • Pointers (limited)
      • `DescriptorHandle` for Bindless Descriptor Access
      • Extensions
      • Multi-level break
      • Force inlining
      • Error handling
      • Special Scoping Syntax
      • User Defined Attributes (Experimental)
    • Modules and Access Control
      • Defining a Module
      • Importing a Module
      • Access Control
      • Organizing File Structure of Modules
      • Legacy Modules
    • Capabilities
      • Capability Atoms and Capability Requirements
      • Conflicting Capabilities
      • Capabilities Between Parent and Members
      • Capabilities Between Subtype and Supertype
      • Capabilities Between Requirement and Implementation
      • Capabilities of Functions
      • Capability Aliases
      • Validation of Capability Requirements
    • Interfaces and Generics
      • Interfaces
      • Generics
      • Supported Constructs in Interface Definitions
      • Associated Types
      • Generic Value Parameters
      • Type Equality Constraints
      • Interface-typed Values
      • Extending a Type with Additional Interface Conformances
      • `is` and `as` Operator
      • Generic Interfaces
      • Generic Extensions
      • Extensions to Interfaces
      • Variadic Generics
      • Builtin Interfaces
    • Automatic Differentiation
      • Auto-diff operations `fwd_diff` and `bwd_diff`
      • Differentiable Type System
      • User-Defined Derivative Functions
      • Using Auto-diff with Generics
      • Using Auto-diff with Interface Requirements and Interface Types
      • Primal Substitute Functions
      • Working with Mixed Differentiable and Non-Differentiable Code
      • Higher-Order Differentiation
      • Restrictions and Known Issues
      • Reference
    • Compiling Code with Slang
      • Concepts
      • Command-Line Compilation with `slangc`
      • Using the Compilation API
      • Multithreading
      • Compiler Options
      • Debugging
    • Using the Reflection API
      • Compiling a Program
      • Types and Variables
      • Layout for Types and Variables
      • Programs and Scopes
      • Calculating Cumulative Offsets
      • Determining Whether Parameters Are Used
      • Conclusion
    • Supported Compilation Targets
      • Background and Terminology
      • Direct3D 11
      • Direct3D 12
      • Vulkan
      • OpenGL
      • Metal
      • CUDA and OptiX
      • CPU Compute
      • WebGPU
      • Summary
    • Link-time Specialization and Module Precompilation
      • Link-time Constants
      • Link-time Types
      • Providing Default Settings
      • Using Precompiling Modules with the API
      • Additional Remarks
    • language slang 2026
      • The Legacy Slang Language
      • Slang 2025
      • Slang 2026
    • Special Topics
      • Handling Matrix Layout Differences on Different Platforms
        • Two conventions of matrix transform math
        • Discussion
        • Matrix Layout
        • Overriding default matrix layout
      • Obfuscation
        • Obfuscation in Slang
        • Using An Obfuscated Module
        • Accessing Source Maps
        • Accessing Source Maps without Files
        • Emit Source Maps
        • Issues/Future Work
      • Interoperation with Target-Specific Code
        • Defining Intrinsic Functions for Textual Targets
        • Defining Intrinsic Types
        • Injecting Preludes
        • Managing Cross-Platform Code
        • Inline SPIRV Assembly
      • Uniformity Analysis
        • Treat Values as Uniform
        • Treat Function Return Values as Non-uniform
    • Target-Specific Features
      • SPIR-V-Specific Functionalities
        • Experimental support for the older versions of SPIR-V
        • Memory model
        • Combined texture sampler
        • System-Value semantics
        • Using SV_InstanceID and SV_VertexID with SPIR-V target
        • Behavior of `discard` after SPIR-V 1.6
        • Supported HLSL features when targeting SPIR-V
        • Unsupported GLSL keywords when targeting SPIR-V
        • Supported atomic types for each target
        • ConstantBuffer, StructuredBuffer and ByteAddressBuffer
        • ParameterBlock for SPIR-V target
        • Push Constants
        • Specialization Constants
        • SPIR-V specific Attributes
        • Multiple entry points support
        • Global memory pointers
        • Matrix type translation
        • Legalization
        • Tessellation
        • SPIR-V specific Compiler options
      • Metal-Specific Functionalities
        • Entry Point Parameter Handling
        • System-Value semantics
        • Interpolation Modifiers
        • Resource Types
        • Array Types
        • Matrix Layout
        • Mesh Shader Support
        • Header Inclusions and Namespace
        • Parameter blocks and Argument Buffers
        • Struct Parameter Flattening
        • Return Value Handling
        • Value Type Conversion
        • Conservative Rasterization
        • Address Space Assignment
        • Explicit Parameter Binding
        • Specialization Constants
      • WGSL-Specific Functionalities
        • System-Value semantics
        • Supported HLSL features when targeting WGSL
        • Supported atomic types
        • ConstantBuffer, (RW/RasterizerOrdered)StructuredBuffer, (RW/RasterizerOrdered)ByteAddressBuffer
        • Interlocked operations
        • Entry Point Parameter Handling
        • Parameter blocks
        • Write-only Textures
        • Pointers
        • Address Space Assignment
        • Matrix type translation
        • Explicit Parameter Binding
        • Specialization Constants
      • GLSL-Specific Functionalities
        • Combined Texture Sampler
        • System-Value Semantics
        • `discard` Statement
        • HLSL Features Supported in GLSL
        • Atomic Types
        • Buffer Types
        • Matrix Layout
        • Entry Points
        • Specialization Constants
        • Attributes and Layout Qualifiers
        • GLSL-Specific Compiler Options
    • Reference
      • Capability Profiles
      • Capability Atoms
        • Targets
        • Stages
        • Versions
        • Extensions
        • Compound Capabilities
        • Other

Metal-Specific Functionalities

This chapter provides information for Metal-specific functionalities and behaviors in Slang.

Entry Point Parameter Handling

Slang performs several transformations on entry point parameters when targeting Metal:

  • Struct parameters are flattened to eliminate nested structures
  • Input parameters with varying inputs are packed into a single struct
  • System value semantics are translated to Metal attributes
  • Parameters without semantics are given automatic attribute indices

Limitation: isParameterLocationUsed for varying inputs

Because Metal entry point varying inputs are packed into a single [[stage_in]] struct parameter during legalization, IMetadata::isParameterLocationUsed cannot distinguish between used and unused individual varying inputs. The metadata is recorded at the struct level, so if any varying input is used, all varying input locations covered by the struct will be reported as used. This differs from SPIR-V, where each varying input becomes a separate global parameter that can be individually tracked.

This limitation does not affect non-varying resource types (e.g. descriptor table slots), which are tracked individually.

System-Value semantics

The system-value semantics are translated to the following Metal attributes:

SV semantic name Metal attribute
SV_Position [[position]]
SV_Coverage [[sample_mask]]
SV_Depth [[depth(any)]]
SV_DepthGreaterEqual [[depth(greater)]]
SV_DepthLessEqual [[depth(less)]]
SV_DispatchThreadID [[thread_position_in_grid]]
SV_FragInvocationCount (Not supported)
SV_FragSize (Not supported)
SV_GroupID [[threadgroup_position_in_grid]]
SV_GroupThreadID [[thread_position_in_threadgroup]]
SV_GroupIndex Calculated from SV_GroupThreadID and group extents
SV_InstanceID [[instance_id]]
SV_IsFrontFace [[front_facing]]
SV_PointSize [[point_size]]
SV_PointCoord [[point_coord]]
SV_PrimitiveID [[primitive_id]]
SV_RenderTargetArrayIndex [[render_target_array_index]]
SV_SampleIndex [[sample_id]]
SV_Target<N> [[color(N)]]
SV_VertexID [[vertex_id]]
SV_ViewportArrayIndex [[viewport_array_index]]
SV_StartVertexLocation [[base_vertex]]
SV_StartInstanceLocation [[base_instance]]
SV_VulkanInstanceID [[instance_id]]
SV_VulkanSamplePosition (Not supported)
SV_VulkanVertexID [[vertex_id]]

Custom semantics are mapped to user attributes:

  • [[user(SEMANTIC_NAME)]] For non-system value semantics
  • [[user(SEMANTIC_NAME_INDEX)]] When semantic has an index

Interpolation Modifiers

Slang maps interpolation modifiers to Metal’s interpolation attributes:

Slang Interpolation Metal Attribute
nointerpolation [[flat]]
noperspective [[center_no_perspective]]
linear [[sample_no_perspective]]
sample [[sample_perspective]]
centroid [[center_perspective]]

Resource Types

Resource types are translated with appropriate Metal qualifiers:

Slang Type Metal Translation
Texture2D texture2d
RWTexture2D texture2d
ByteAddressBuffer uint32_t device*
StructuredBuffer<T> device* T
ConstantBuffer<T> constant* T
Slang Type Metal Translation
Texture1D texture1d
Texture1DArray texture1d_array
RWTexture1D texture1d
RWTexture1DArray texture1d_array
Texture2D texture2d
Texture2DArray texture2d_array
RWTexture2D texture2d
RWTexture2DArray texture2d_array
Texture3D texture3d
RWTexture3D texture3d
TextureCube texturecube
TextureCubeArray texturecube_array
Buffer<T> device* T
RWBuffer<T> device* T
ByteAddressBuffer device* uint32_t
RWByteAddressBuffer device* uint32_t
StructuredBuffer<T> device* T
RWStructuredBuffer<T> device* T
AppendStructuredBuffer<T> device* T
ConsumeStructuredBuffer<T> device* T
ConstantBuffer<T> constant* T
SamplerState sampler
SamplerComparisonState sampler
RaytracingAccelerationStructure (Not supported)
RasterizerOrderedTexture2D texture2d [[raster_order_group(0)]]
RasterizerOrderedBuffer<T> device* T [[raster_order_group(0)]]

Raster-ordered access resources receive the [[raster_order_group(0)]] attribute, for example texture2d<float, access::read_write> tex [[raster_order_group(0)]].

Array Types

Array types in Metal are declared using the array template:

Slang Type Metal Translation
ElementType[Size] array<ElementType, Size>

Matrix Layout

Metal exclusively uses column-major matrix layout. Slang automatically handles the translation of matrix operations to maintain correct semantics:

  • Matrix multiplication is transformed to account for layout differences
  • Matrix types are declared as matrix<T, Columns, Rows>, for example float3x4 is represented as matrix<float, 3, 4>

Mesh Shader Support

Mesh shaders can be targeted using the following types and syntax. The same as task/mesh shaders generally in Slang.

[outputtopology("triangle")]
[numthreads(12, 1, 1)]
void meshMain(
    in uint tig: SV_GroupIndex,
    in payload MeshPayload meshPayload,
    OutputVertices<Vertex, MAX_VERTS> verts,
    OutputIndices<uint3, MAX_PRIMS> triangles,
    OutputPrimitives<Primitive, MAX_PRIMS> primitives
    )

Header Inclusions and Namespace

When targeting Metal, Slang automatically includes the following headers, these are available to any intrinsic code.

#include <metal_stdlib>
#include <metal_math>
#include <metal_texture>
using namespace metal;

Parameter blocks and Argument Buffers

ParameterBlock values are translated into Argument Buffers potentially containing nested resources. For example, this Slang code…

struct MyParameters
{
    int x;
    int y;
    StructuredBuffer<float> buffer1;
    RWStructuredBuffer<uint3> buffer2;
}

ParameterBlock<MyParameters> gObj;

void main(){ ... gObj ... }

… results in this Metal output:

struct MyParameters
{
    int x;
    int y;
    float device* buffer1;
    uint3 device* buffer2;
};

[[kernel]] void main(MyParameters constant* gObj [[buffer(1)]])

Struct Parameter Flattening

When targeting Metal, top-level nested struct parameters are automatically flattened. For example:

struct NestedStruct
{
    float2 uv;
};
struct InputStruct
{
    float4 position;
    float3 normal;
    NestedStruct nested;
};

Will be flattened to:

struct InputStruct
{
    float4 position;
    float3 normal;
    float2 uv;
};

Return Value Handling

Non-struct return values from entry points are automatically wrapped in a struct with appropriate semantics. For example:

float4 main() : SV_Target
{
    return float4(1,2,3,4);
}

becomes:

struct FragmentOutput
{
    float4 value : SV_Target;
};
FragmentOutput main()
{
    return { float4(1,2,3,4) };
}

Value Type Conversion

Metal enforces strict type requirements for certain operations. Slang automatically performs the following conversions:

  • Vector size expansion (e.g., float2 to float4), for example when the user specified float2 but the semantic type in Metal is float4.
  • Image store value expansion to 4-components

For example:

RWTexture2D<float2> tex;
tex[coord] = float2(1,2);  // Automatically expanded to float4(1,2,0,0)

Conservative Rasterization

Since Metal doesn’t support conservative rasterization, SV_InnerCoverage is always false.

Address Space Assignment

Metal requires explicit address space qualifiers. Slang automatically assigns appropriate address spaces:

Variable Type Metal Address Space
Local Variables thread
Global Variables device
Uniform Buffers constant
RW/Structured Buffers device
Group Shared threadgroup
Parameter Blocks constant

Explicit Parameter Binding

The HLSL :register() semantic is respected when emitting Metal code.

Since Metal does not differentiate between a constant buffer, a shader resource (read-only) buffer and an unordered access buffer, Slang will map register(tN), register(uN) and register(bN) to [[buffer(N)]] when such register semantic is declared on a buffer-typed parameter.

spaceN specifiers inside register semantics are ignored.

The [vk::location(N)] attributes on stage input/output parameters are respected.

Specialization Constants

Specialization constants declared with the [SpecializationConstant] or [vk::constant_id] attribute will be translated into a function_constant when generating Metal source. For example:

[vk::constant_id(7)]
const int a = 2;

Translates to:

constant int fc_a_0 [[function_constant(7)]];
constant int a_0 = is_function_constant_defined(fc_a_0) ? fc_a_0 : 2;