yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
05f0f5603
master
layout: user-guide permalink: /user-guide/metal-target-specific
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
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 examplefloat3x4is represented asmatrix<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.,
float2tofloat4), for example when the user specifiedfloat2but the semantic type in Metal isfloat4. - 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;
1--- 2layout : user-guide 3permalink : /user-guide/metal-target-specific 4--- 5 6# Metal-Specific Functionalities 7 8This chapter provides information for Metal-specific functionalities and 9behaviors in Slang. 10 11## Entry Point Parameter Handling 12 13Slang performs several transformations on entry point parameters when targeting Metal: 14 15- Struct parameters are flattened to eliminate nested structures 16- Input parameters with varying inputs are packed into a single struct 17- System value semantics are translated to Metal attributes 18- Parameters without semantics are given automatic attribute indices 19 20## System-Value semantics 21 22The system-value semantics are translated to the following Metal attributes: 23 24| SV semantic name | Metal attribute | 25| --------------------------- | ---------------------------------------------------- | 26| `SV_Position` | `[[position]]` | 27| `SV_Coverage` | `[[sample_mask]]` | 28| `SV_Depth` | `[[depth(any)]]` | 29| `SV_DepthGreaterEqual` | `[[depth(greater)]]` | 30| `SV_DepthLessEqual` | `[[depth(less)]]` | 31| `SV_DispatchThreadID` | `[[thread_position_in_grid]]` | 32| `SV_FragInvocationCount` | `(Not supported)` | 33| `SV_FragSize` | `(Not supported)` | 34| `SV_GroupID` | `[[threadgroup_position_in_grid]]` | 35| `SV_GroupThreadID` | `[[thread_position_in_threadgroup]]` | 36| `SV_GroupIndex` | Calculated from `SV_GroupThreadID` and group extents | 37| `SV_InstanceID` | `[[instance_id]]` | 38| `SV_IsFrontFace` | `[[front_facing]]` | 39| `SV_PointSize` | `[[point_size]]` | 40| `SV_PointCoord` | `[[point_coord]]` | 41| `SV_PrimitiveID` | `[[primitive_id]]` | 42| `SV_RenderTargetArrayIndex` | `[[render_target_array_index]]` | 43| `SV_SampleIndex` | `[[sample_id]]` | 44| `SV_Target<N>` | `[[color(N)]]` | 45| `SV_VertexID` | `[[vertex_id]]` | 46| `SV_ViewportArrayIndex` | `[[viewport_array_index]]` | 47| `SV_StartVertexLocation` | `[[base_vertex]]` | 48| `SV_StartInstanceLocation` | `[[base_instance]]` | 49| `SV_VulkanInstanceID` | `[[instance_id]]` | 50| `SV_VulkanSamplePosition` | `(Not supported)` | 51| `SV_VulkanVertexID` | `[[vertex_id]]` | 52 53Custom semantics are mapped to user attributes: 54 55- `[[user(SEMANTIC_NAME)]]` For non-system value semantics 56- `[[user(SEMANTIC_NAME_INDEX)]]` When semantic has an index 57 58## Interpolation Modifiers 59 60Slang maps interpolation modifiers to Metal's interpolation attributes: 61 62| Slang Interpolation | Metal Attribute | 63| ------------------- | --------------------------- | 64| `nointerpolation` | `[[flat]]` | 65| `noperspective` | `[[center_no_perspective]]` | 66| `linear` | `[[sample_no_perspective]]` | 67| `sample` | `[[sample_perspective]]` | 68| `centroid` | `[[center_perspective]]` | 69 70## Resource Types 71 72Resource types are translated with appropriate Metal qualifiers: 73 74| Slang Type | Metal Translation | 75| --------------------- | ------------------ | 76| `Texture2D` | `texture2d` | 77| `RWTexture2D` | `texture2d` | 78| `ByteAddressBuffer` | `uint32_t device*` | 79| `StructuredBuffer<T>` | `device* T` | 80| `ConstantBuffer<T>` | `constant* T` | 81 82| Slang Type | Metal Translation | 83| --------------------------------- | ------------------------------------- | 84| `Texture1D` | `texture1d` | 85| `Texture1DArray` | `texture1d_array` | 86| `RWTexture1D` | `texture1d` | 87| `RWTexture1DArray` | `texture1d_array` | 88| `Texture2D` | `texture2d` | 89| `Texture2DArray` | `texture2d_array` | 90| `RWTexture2D` | `texture2d` | 91| `RWTexture2DArray` | `texture2d_array` | 92| `Texture3D` | `texture3d` | 93| `RWTexture3D` | `texture3d` | 94| `TextureCube` | `texturecube` | 95| `TextureCubeArray` | `texturecube_array` | 96| `Buffer<T>` | `device* T` | 97| `RWBuffer<T>` | `device* T` | 98| `ByteAddressBuffer` | `device* uint32_t` | 99| `RWByteAddressBuffer` | `device* uint32_t` | 100| `StructuredBuffer<T>` | `device* T` | 101| `RWStructuredBuffer<T>` | `device* T` | 102| `AppendStructuredBuffer<T>` | `device* T` | 103| `ConsumeStructuredBuffer<T>` | `device* T` | 104| `ConstantBuffer<T>` | `constant* T` | 105| `SamplerState` | `sampler` | 106| `SamplerComparisonState` | `sampler` | 107| `RaytracingAccelerationStructure` | `(Not supported)` | 108| `RasterizerOrderedTexture2D` | `texture2d [[raster_order_group(0)]]` | 109| `RasterizerOrderedBuffer<T>` | `device* T [[raster_order_group(0)]]` | 110 111Raster-ordered access resources receive the `[[raster_order_group(0)]]` 112attribute, for example `texture2d<float, access::read_write> tex 113[[raster_order_group(0)]]`. 114 115## Array Types 116 117Array types in Metal are declared using the array template: 118 119| Slang Type | Metal Translation | 120| ------------------- | -------------------------- | 121| `ElementType[Size]` | `array<ElementType, Size>` | 122 123## Matrix Layout 124 125Metal exclusively uses column-major matrix layout. Slang automatically handles 126the translation of matrix operations to maintain correct semantics: 127 128- Matrix multiplication is transformed to account for layout differences 129- Matrix types are declared as `matrix<T, Columns, Rows>`, for example 130`float3x4` is represented as `matrix<float, 3, 4>` 131 132## Mesh Shader Support 133 134Mesh shaders can be targeted using the following types and syntax. The same as task/mesh shaders generally in Slang. 135 136``` slang 137[outputtopology("triangle")] 138[numthreads(12, 1, 1)] 139void meshMain( 140in uint tig: SV_GroupIndex, 141in payload MeshPayload meshPayload, 142OutputVertices<Vertex, MAX_VERTS> verts, 143OutputIndices<uint3, MAX_PRIMS> triangles, 144OutputPrimitives<Primitive, MAX_PRIMS> primitives 145) 146``` 147 148## Header Inclusions and Namespace 149 150When targeting Metal, Slang automatically includes the following headers, these 151are available to any intrinsic code. 152 153``` cpp 154#include <metal_stdlib> 155#include <metal_math> 156#include <metal_texture> 157using namespace metal ; 158``` 159 160## Parameter blocks and Argument Buffers 161 162`ParameterBlock` values are translated into _Argument Buffers_ potentially 163containing nested resources. For example, this Slang code... 164 165``` slang 166struct MyParameters 167{ 168int x; 169int y; 170StructuredBuffer<float> buffer1; 171RWStructuredBuffer<uint3> buffer2; 172} 173 174ParameterBlock<MyParameters> gObj; 175 176void main(){ ... gObj ... } 177``` 178 179... results in this Metal output: 180 181``` cpp 182struct MyParameters 183{ 184int x ; 185int y ; 186float device * buffer1 ; 187uint3 device * buffer2 ; 188}; 189 190[[ kernel ]] void main ( MyParameters constant * gObj [[ buffer ( 1 )]]) 191``` 192 193## Struct Parameter Flattening 194 195When targeting Metal, top-level nested struct parameters are automatically 196flattened. For example: 197 198``` slang 199struct NestedStruct 200{ 201float2 uv; 202}; 203struct InputStruct 204{ 205float4 position; 206float3 normal; 207NestedStruct nested; 208}; 209``` 210 211Will be flattened to: 212 213``` cpp 214struct InputStruct 215{ 216float4 position ; 217float3 normal ; 218float2 uv ; 219}; 220``` 221 222## Return Value Handling 223 224Non-struct return values from entry points are automatically wrapped in a 225struct with appropriate semantics. For example: 226 227``` slang 228float4 main() : SV_Target 229{ 230return float4(1,2,3,4); 231} 232``` 233 234becomes: 235 236``` c++ 237struct FragmentOutput 238{ 239float4 value : SV_Target; 240}; 241FragmentOutput main() 242{ 243return { float4(1,2,3,4) }; 244} 245``` 246 247## Value Type Conversion 248 249Metal enforces strict type requirements for certain operations. Slang 250automatically performs the following conversions: 251 252- Vector size expansion (e.g., `float2` to `float4`), for example when the user 253specified `float2` but the semantic type in Metal is `float4`. 254- Image store value expansion to 4-components 255 256For example: 257 258``` slang 259RWTexture2D<float2> tex; 260tex[coord] = float2(1,2); // Automatically expanded to float4(1,2,0,0) 261``` 262 263## Conservative Rasterization 264 265Since Metal doesn't support conservative rasterization, SV_InnerCoverage is always false. 266 267## Address Space Assignment 268 269Metal requires explicit address space qualifiers. Slang automatically assigns appropriate address spaces: 270 271| Variable Type | Metal Address Space | 272| --------------------- | ------------------- | 273| Local Variables | `thread` | 274| Global Variables | `device` | 275| Uniform Buffers | `constant` | 276| RW/Structured Buffers | `device` | 277| Group Shared | `threadgroup` | 278| Parameter Blocks | `constant` | 279 280## Explicit Parameter Binding 281 282The HLSL `:register()` semantic is respected when emitting Metal code. 283 284Since 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. 285 286`spaceN` specifiers inside `register` semantics are ignored. 287 288The `[vk::location(N)]` attributes on stage input/output parameters are respected. 289 290## Specialization Constants 291 292Specialization constants declared with the `[SpecializationConstant]` or `[vk::constant_id]` attribute will be translated into a `function_constant` when generating Metal source. 293For example: 294 295``` csharp 296[vk::constant_id(7)] 297const int a = 2; 298``` 299 300Translates to: 301 302``` metal 303constant int fc_a_0 [[function_constant(7)]]; 304constant int a_0 = is_function_constant_defined(fc_a_0) ? fc_a_0 : 2; 305```