Migrating to Slang from GLSL

Overview

This guide provides a reference for migrating GLSL shaders to Slang.

Type and Syntax Reference

When converting GLSL shaders to Slang, you’ll need to translate GLSL types and syntax to their Slang equivalents.

Scalar Types

GLSL Type

Slang Type

Description

float

float

32-bit floating point

float16_t

half

16-bit floating point

int

int

32-bit signed integer

uint

uint

32-bit unsigned integer

bool

bool

Boolean value

double

double

64-bit floating point

int8_t

int8_t

8-bit signed integer

uint8_t

uint8_t

8-bit unsigned integer

int16_t

int16_t

16-bit signed integer

uint16_t

uint16_t

16-bit unsigned integer

int64_t

int64_t

64-bit signed integer

uint64_t

uint64_t

64-bit unsigned integer

Vector Types

GLSL Type

Slang Type

Description

vec2

float2

2-component float vector

vec3

float3

3-component float vector

vec4

float4

4-component float vector

f16vec2

half2

2-component half-precision float vector

f16vec3

half3

3-component half-precision float vector

f16vec4

half4

4-component half-precision float vector

ivec2

int2

2-component int vector

ivec3

int3

3-component int vector

ivec4

int4

4-component int vector

uvec2

uint2

2-component uint vector

uvec3

uint3

3-component uint vector

uvec4

uint4

4-component uint vector

bvec2

bool2

2-component boolean vector

bvec3

bool3

3-component boolean vector

bvec4

bool4

4-component boolean vector

dvec2

double2

2-component double vector

dvec3

double3

3-component double vector

dvec4

double4

4-component double vector

Matrix Types

GLSL Type

Slang Type

Description

mat2

float2x2

2×2 float matrix

mat3

float3x3

3×3 float matrix

mat4

float4x4

4×4 float matrix

mat2x3

float2x3

2×3 float matrix

mat2x4

float2x4

2×4 float matrix

mat3x2

float3x2

3×2 float matrix

mat3x4

float3x4

3×4 float matrix

mat4x2

float4x2

4×2 float matrix

mat4x3

float4x3

4×3 float matrix

f16mat2

half2x2

2×2 half-precision float matrix

f16mat3

half3x3

3×3 half-precision float matrix

f16mat4

half4x4

4×4 half-precision float matrix

f16mat2x3

half2x3

2×3 half-precision float matrix

f16mat2x4

half2x4

2×4 half-precision float matrix

f16mat3x2

half3x2

3×2 half-precision float matrix

f16mat3x4

half3x4

3×4 half-precision float matrix

f16mat4x2

half4x2

4×2 half-precision float matrix

f16mat4x3

half4x3

4×3 half-precision float matrix

Vector/Matrix Construction

GLSL:

vec4 color = vec4(1.0, 0.5, 0.2, 1.0);
mat4 transform = mat4(
    vec4(1.0, 0.0, 0.0, 0.0),
    vec4(0.0, 1.0, 0.0, 0.0),
    vec4(0.0, 0.0, 1.0, 0.0),
    vec4(0.0, 0.0, 0.0, 1.0)
);

Slang:

float4 color = float4(1.0, 0.5, 0.2, 1.0);
float4x4 transform = float4x4(
    float4(1.0, 0.0, 0.0, 0.0),
    float4(0.0, 1.0, 0.0, 0.0),
    float4(0.0, 0.0, 1.0, 0.0),
    float4(0.0, 0.0, 0.0, 1.0)
);

Matrix Operations

GLSL:

mat4 a, b, c;
vec4 v;

// Matrix multiplication
c = a * b;

// Vector transformation (vector is treated as a row vector)
vec4 transformed = v * a;  // row vector * matrix

Slang:

float4x4 a, b, c;
float4 v;

// Matrix multiplication
c = mul(a, b);

// Vector transformation (vector is treated as a column vector)
float4 transformed = mul(a, v);  // matrix * column vector

Note: Slang uses the mul() function for matrix multiplication rather than the * operator. Also, vectors are treated as column vectors in Slang, while they’re treated as row vectors in GLSL, so the order of arguments is inverted.

Shader Inputs and Outputs

GLSL and Slang handle shader inputs and outputs differently. Here’s a fragment/pixel shader example:

GLSL:

// Fragment shader input
in vec2 texCoord;

// Fragment shader output
layout(location = 0) out vec4 fragColor;

void main() {
    // Use texCoord to sample a texture
    fragColor = vec4(texCoord, 0.0, 1.0);
}

Slang (Method 1 - Using structures):

// Input structure
struct PSInput {
    float2 texCoord : TEXCOORD0;
};

// Output structure
struct PSOutput {
    float4 color : SV_Target0;
};

// Pixel shader using structures
[shader("pixel")]
PSOutput main(PSInput input) {
    PSOutput output;
    
    // Use input.texCoord to sample a texture
    output.color = float4(input.texCoord, 0.0, 1.0);
    
    return output;
}

Slang (Method 2 - Direct parameters):

// Pixel shader using direct parameters
[shader("pixel")]
float4 main(float2 texCoord : TEXCOORD0) : SV_Target0 {
    // Use texCoord to sample a texture
    return float4(texCoord, 0.0, 1.0);
}

Both Slang methods produce the same result, but Method 1 is more organized for complex shaders with many inputs and outputs, while Method 2 is more concise for simple shaders.

Built-in Variables

GLSL provides built-in variables that can be accessed directly in shaders, while Slang requires these variables to be explicitly declared as inputs or outputs in shader entry point functions. Unlike regular shader inputs and outputs which you define yourself, built-in variables provide access to system values like vertex IDs, screen positions, etc.

Example: Minimal Vertex Shader with Built-in Variables

Here’s a simplified example showing how built-in variables work in both GLSL and Slang:

GLSL:

#version 460

// No need to declare gl_VertexID - it's implicitly available

void main() {
    // Access input built-in variable directly
    int vertID = gl_VertexID;
    
    // Set position based on vertex ID
    float x = (vertID == 0) ? -0.5 : ((vertID == 1) ? 0.5 : 0.0);
    float y = (vertID == 2) ? 0.5 : -0.5;
    
    // Set output built-in variable directly
    gl_Position = vec4(x, y, 0.0, 1.0);
}

Slang:

// Slang: Built-in variables must be explicitly declared in the function signature
[shader("vertex")]
float4 main(uint vertexID : SV_VertexID) : SV_Position {
    // Input built-in is passed as a function parameter
    
    // Calculate position based on vertex ID
    float x = (vertexID == 0) ? -0.5 : ((vertexID == 1) ? 0.5 : 0.0);
    float y = (vertexID == 2) ? 0.5 : -0.5;
    
    // Output built-in is returned from the function
    return float4(x, y, 0.0, 1.0);
}

Notice the key differences:

  1. In GLSL, gl_VertexID (input) and gl_Position (output) are accessed directly as global variables

  2. In Slang, the input SV_VertexID is a function parameter, and the output SV_Position is the function return value

For more complex shaders, you can use structures for inputs and outputs as shown in the previous section.

Built-in Variables Reference

The following table maps GLSL built-in variables to their corresponding Slang system value semantics across standard shader stages. In GLSL, these variables are accessed directly as globals, while in Slang they must be declared explicitly in function signatures with appropriate semantic annotations.

GLSL Built-in

Slang System Value

gl_BaseInstance

SV_StartInstanceLocation

gl_BaseVertex

SV_StartVertexLocation

gl_BaryCoordEXT

SV_Barycentrics

gl_ClipDistance

SV_ClipDistance

gl_CullDistance

SV_CullDistance

gl_CullPrimitiveEXT

SV_CullPrimitive

gl_DrawID

SV_DrawIndex

gl_FragCoord

SV_Position

gl_FragDepth

SV_Depth

gl_FragStencilRefEXT

SV_StencilRef

gl_FrontFacing

SV_IsFrontFace

gl_FullyCoveredEXT

SV_InnerCoverage

gl_GlobalInvocationID

SV_DispatchThreadID

gl_InstanceID

SV_InstanceID

gl_InvocationID

SV_GSInstanceID/SV_OutputControlPointID

gl_Layer

SV_RenderTargetArrayIndex

gl_LocalInvocationID

SV_GroupThreadID

gl_LocalInvocationIndex

SV_GroupIndex

gl_PointSize

SV_PointSize

gl_Position

SV_Position

gl_PrimitiveID

SV_PrimitiveID

gl_PrimitiveShadingRateEXT

SV_ShadingRate

gl_SampleID

SV_SampleIndex

gl_SampleMask

SV_Coverage

gl_ShadingRateEXT

SV_ShadingRate

gl_SubgroupInvocationID

SV_WaveLaneIndex

gl_SubgroupSize

SV_WaveLaneCount

gl_TessCoord

SV_DomainLocation

gl_TessLevelInner

SV_InsideTessFactor

gl_TessLevelOuter

SV_TessFactor

gl_VertexIndex

SV_VertexID

gl_ViewIndex

SV_ViewID

gl_ViewportIndex

SV_ViewportArrayIndex

gl_WorkGroupID

SV_GroupID

Ray Tracing Built-ins

Ray tracing built-ins in Slang are accessed through function calls rather than system value semantics. The following table maps GLSL ray tracing built-ins to their corresponding Slang functions:

GLSL Built-in

Slang Function

gl_HitKindEXT

HitKind()

gl_HitTEXT

RayTCurrent()

gl_InstanceCustomIndexEXT

InstanceIndex()

gl_InstanceID

InstanceID()

gl_LaunchIDEXT

DispatchRaysIndex()

gl_LaunchSizeEXT

DispatchRaysDimensions()

gl_ObjectRayDirectionEXT

ObjectRayDirection()

gl_ObjectRayOriginEXT

ObjectRayOrigin()

gl_RayTmaxEXT

RayTCurrent()

gl_RayTminEXT

RayTMin()

gl_WorldRayDirectionEXT

WorldRayDirection()

gl_WorldRayOriginEXT

WorldRayOrigin()

Built-in Functions and Operators

When porting GLSL shaders to Slang, most common mathematical functions (sin, cos, tan, pow, sqrt, abs, etc.) share identical names in both languages. However, there are several important differences to be aware of, listed below:

Key Function Differences

GLSL

Slang

Description

mix(x, y, a)

lerp(x, y, a)

Linear interpolation

fract(x)

frac(x)

Fractional part of x

inversesqrt(x)

rsqrt(x)

Inverse square root (1/sqrt)

atan(y, x)

atan2(y, x)

Arc tangent of y/x

dFdx(p)

ddx(p)

Derivative with respect to screen-space x

dFdy(p)

ddy(p)

Derivative with respect to screen-space y

m1 * m2 (matrix multiply)

mul(m1, m2)

Matrix multiplication

v * m (row vector)

mul(m, v) (column vector)

Vector-matrix multiplication

Resource Handling

This section covers how to convert GLSL resource declarations to Slang, including different buffer types, textures, and specialized resources.

Resource Binding Models

Slang supports three different binding syntax options to accommodate both HLSL-style and GLSL-style resource declarations:

GLSL Binding Model

// GLSL uses binding and set numbers
layout(binding = 0, set = 0) uniform UniformBufferA { ... };

Slang Binding Models

Option 1: HLSL Register Syntax
// Using register semantics with space (equivalent to set)
ConstantBuffer<UniformBufferA> bufferA : register(b0, space0);
Option 2: GLSL-style Layout Syntax
// Using GLSL-style binding with [[vk::binding(binding, set)]]
[[vk::binding(0, 0)]]
ConstantBuffer<UniformBufferA> bufferA;
Option 3: Direct GLSL Layout Syntax
// Using layout syntax identical to GLSL
layout(binding = 0, set = 0) ConstantBuffer<UniformBufferA> bufferA;

All binding syntax options work the same way for all resource types (ConstantBuffer, Texture2D, RWStructuredBuffer, etc.). The GLSL-style options (2 and 3) can be particularly helpful when porting GLSL shaders without changing the binding model.

Buffer Types

Resource Type

GLSL

Slang

Description

Uniform Buffer

uniform Buffer {...}

ConstantBuffer<T>

Read-only constant data

Storage Buffer

buffer Buffer {...}

RWStructuredBuffer<T>

Read-write structured data

Read-only Storage Buffer

readonly buffer Buffer {...}

StructuredBuffer<T>

Read-only structured data

Example in GLSL:

#version 460

layout(std140, binding = 0) uniform Params {
    float scale;
};

struct Data {
    vec3 value;
};

layout(std430, binding = 1) buffer Storage {
    Data data;
};

layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
void main() {
    float s = scale;
    data.value *= s;
}

Example in Slang:

struct Params {
    float scale;
};

layout(binding = 0) ConstantBuffer<Params> params;

struct Data {
    float3 value;
};

layout(binding = 1) RWStructuredBuffer<Data> data;

[shader("compute")]
[numthreads(1, 1, 1)]
void main() {
    float s = params.scale;
    data[0].value *= s;
}

Key differences to note:

  1. Slang uses the RW prefix to distinguish read-write resources from read-only ones

  2. In Slang, structured buffers must be indexed even for a single element (e.g., data[0].value)

  3. In Slang, all buffer members are accessed through the buffer variable name (e.g., params.scale, data[0].value)

Texture Resources

This section covers the declaration and usage of texture resources in Slang compared to GLSL.

Combined Texture Samplers

GLSL:

// Texture declaration
layout(binding = 0) uniform sampler2D inputTexture;
layout(location = 0) out vec4 fragColor;

void main() {
    // Simple texture sampling and copy to output
    vec2 uv = gl_FragCoord.xy / vec2(1280.0, 720.0);
    fragColor = texture(inputTexture, uv);
}

Slang:

// Texture declaration
layout(binding = 0) Sampler2D inputTexture;

[shader("pixel")]
float4 main(float4 position : SV_Position) : SV_Target0 {
    // Simple texture sampling and return
    float2 uv = position.xy / float2(1280.0, 720.0);
    return inputTexture.Sample(uv);
}

Texture Type Mapping:

GLSL Type

Slang Type

Description

sampler1D

Sampler1D

1D texture with built-in sampler

sampler2D

Sampler2D

2D texture with built-in sampler

sampler3D

Sampler3D

3D texture with built-in sampler

samplerCube

SamplerCube

Cube texture with built-in sampler

sampler2DArray

Sampler2DArray

2D texture array with built-in sampler

samplerCubeArray

SamplerCubeArray

Cube texture array with built-in sampler

sampler2DShadow

Sampler2DShadow

Shadow sampler for depth comparisons

isampler2D

Sampler2D<int4>

Integer 2D texture with built-in sampler

usampler2D

Sampler2D<uint4>

Unsigned integer 2D texture with built-in sampler

Texture Function Mapping (Combined Sampler Approach):

GLSL Function

Slang Function

Description

texture(sampler, coord)

sampler.Sample(coord)

Basic texture sampling

textureLod(sampler, coord, lod)

sampler.SampleLevel(coord, lod)

Sample with specific mip level

textureGrad(sampler, coord, ddx, ddy)

sampler.SampleGrad(coord, ddx, ddy)

Sample with explicit derivatives

textureOffset(sampler, coord, offset)

sampler.SampleOffset(coord, offset)

Sample with offset

texelFetch(sampler, coord, lod)

sampler.Load(int3(coord, lod))

Direct texel fetch

textureSize(sampler, lod)

sampler.GetDimensions(lod, width, height)

Get texture dimensions

textureGather(sampler, coord)

sampler.Gather(coord)

Gather four texels

textureGatherOffset(sampler, coord, offset)

sampler.GatherOffset(coord, offset)

Gather with offset

Separate Texture Samplers

GLSL:

// Declare texture and sampler separately
uniform texture2D colorTexture;
uniform sampler texSampler;

void main() {
    vec2 uv = gl_FragCoord.xy / vec2(1280.0, 720.0);
    // Combine texture and sampler for sampling
    vec4 color = texture(sampler2D(colorTexture, texSampler), uv);
    fragColor = color;
}

Slang:

// Declare texture and sampler state separately
Texture2D colorTexture;
SamplerState texSampler;

[shader("pixel")]
float4 main(float4 position : SV_Position) : SV_Target {
    float2 uv = position.xy / float2(1280.0, 720.0);
    // Pass sampler state explicitly to the Sample method
    return colorTexture.Sample(texSampler, uv);
}

Image Resources

This section covers the declaration and usage of image resources in Slang compared to GLSL, including how to perform image load/store operations.

GLSL:

// Image declaration
layout(binding = 4, rgba8) uniform image2D outputImage;

layout(local_size_x = 8, local_size_y = 8) in;
void main() {
    // Get the pixel coordinate for this thread
    ivec2 pixelCoord = ivec2(gl_GlobalInvocationID.xy);
    
    // Simple image store operation (set to red color)
    imageStore(outputImage, pixelCoord, vec4(1.0, 0.0, 0.0, 1.0));
}

Slang:

// Image declaration
layout(binding = 4) RWTexture2D<float4> outputImage;

[shader("compute")]
[numthreads(8, 8, 1)]
void main(uint3 dispatchThreadID : SV_DispatchThreadID) {
    // Get the pixel coordinate for this thread
    int2 pixelCoord = int2(dispatchThreadID.xy);
    
    // Simple image store operation (set to red color)
    outputImage[pixelCoord] = float4(1.0, 0.0, 0.0, 1.0);
}

Image Type Mapping:

GLSL Type

Slang Type

Description

image1D

RWTexture1D<float4>

1D read-write image

image2D

RWTexture2D<float4>

2D read-write image

image3D

RWTexture3D<float4>

3D read-write image

imageCube

RWTextureCube<float4>

Cube read-write image

image2DArray

RWTexture2DArray<float4>

2D array read-write image

iimage2D

RWTexture2D<int4>

Integer 2D read-write image

uimage2D

RWTexture2D<uint4>

Unsigned integer 2D read-write image

Image Function Mapping:

GLSL Function

Slang Function

Description

imageLoad(image, coord)

image[coord] or image.Load(coord)

Read from image

imageStore(image, coord, value)

image[coord] = value or image.Store(coord, value)

Write to image

imageSize(image)

image.GetDimensions(width, height)

Get image dimensions

Shader Entry Point Syntax

GLSL and Slang use fundamentally different approaches for shader entry points. While GLSL always uses a void main() function with implicit inputs/outputs through global variables, Slang uses explicitly typed entry points with decorators and function parameters/return values.

This section provides a general overview of the entry point pattern differences. Detailed shader stage-specific conversion information will be covered in a later section.

Core Entry Point Pattern

GLSL Pattern:

#version 460
// Global inputs (in) and outputs (out)
in type input_name;
out type output_name;

// Global uniforms and resources
uniform type resource_name;

// Always uses void main() with no parameters
void main() {
    // Access inputs and resources directly
    // Write to outputs directly
}

Slang Pattern:

// Shader type specified by decorator
[shader("stage_type")]

// Explicit inputs as parameters, outputs as return value
return_type main(parameter_type param : semantic) : return_semantic {
    // Access inputs through parameters
    // Return output value explicitly
}

Shader Stage Decorators

Shader Stage

Slang Decoration

Vertex

[shader("vertex")]

Hull/Tessellation Control

[shader("hull")]

Domain/Tessellation Evaluation

[shader("domain")]

Geometry

[shader("geometry")]

Pixel/Fragment

[shader("pixel")]

Compute

[shader("compute")]

Amplification/Task

[shader("amplification")]

Mesh

[shader("mesh")]

Ray Generation

[shader("raygeneration")]

Closest Hit

[shader("closesthit")]

Miss

[shader("miss")]

Any Hit

[shader("anyhit")]

Intersection

[shader("intersection")]

Callable

[shader("callable")]

Note: For detailed conversions of specific shader stages including tessellation, geometry, mesh, and ray tracing shaders, see the “Shader Stage-Specific Conversions” section later in this guide.

Shader Stage-Specific Conversions

This section provides mappings for each shader stage from GLSL to Slang, focusing on essential declarations, attributes, and stage-specific functionality.

Vertex Shaders

Core Declaration Mapping

GLSL:

// No special attributes required
void main() {
    gl_Position = /* output position calculation */;
}

Slang:

[shader("vertex")]
float4 main(float3 position : POSITION) : SV_Position {
    return /* output position calculation */;
}

Key Conversion Points

  • Declaration: Add [shader("vertex")] decoration

Fragment/Pixel Shaders

Core Declaration Mapping

GLSL:

// Early depth testing (optional)
layout(early_fragment_tests) in;

// Output color target(s)
layout(location = 0) out vec4 fragColor;

void main() {
    fragColor = /* color calculation */;
}

Slang:

// Early depth testing (optional)
[earlydepthstencil]
[shader("pixel")]
float4 main(float4 position : SV_Position) : SV_Target0 {
    return /* color calculation */;
}

Key Conversion Points

  • Declaration: Add [shader("pixel")] decoration

  • Early Z testing: Use [earlydepthstencil] attribute

  • Multiple outputs: Use a struct with multiple fields with SV_Target0/1/2 semantics

Compute Shaders

Core Declaration Mapping

GLSL:

layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
void main() {
    // Access thread ID via gl_GlobalInvocationID
}

Slang:

[shader("compute")]
[numthreads(8, 8, 1)]
void main(uint3 dispatchThreadID : SV_DispatchThreadID) {
    // Access thread ID via dispatchThreadID parameter
}

Key Conversion Points

  • Thread group size: Replace layout(local_size_x=X...) in with [numthreads(X,Y,Z)]

  • Shared memory: Replace shared with groupshared

  • Barriers: Replace barrier() with GroupMemoryBarrierWithGroupSync()

Hull Shader (Tessellation Control)

Core Declaration Mapping

GLSL:

// Patch size specification
layout(vertices = 3) out;

void main() {
    // Set tessellation levels and compute control points
    gl_TessLevelOuter[0] = 1.0;
    // ...
}

Slang:

// Hull shader requires multiple attributes and a separate patch constant function
[shader("hull")]
[domain("tri")]
[partitioning("fractional_odd")]
[outputtopology("triangle_cw")]
[outputcontrolpoints(3)]
[patchconstantfunc("PatchConstantFunction")]
ControlPoint main(InputPatch<Vertex, 3> patch, uint cpID : SV_OutputControlPointID) {
    // Compute control points
}

// Separate function for tessellation factors
struct PatchTessFactors {
    float4 tessFactor : SV_TessFactor;
    float2 insideTessFactor : SV_InsideTessFactor;
};

PatchTessFactors PatchConstantFunction(InputPatch<Vertex, 3> patch) {
    // Set tessellation levels
}

Key Attribute Mappings

GLSL

Slang

Description

layout(vertices = N) out

[outputcontrolpoints(N)]

Number of control points

Implicit

[domain("tri/quad/isoline")]

Patch domain type

Implicit

[partitioning("integer/fractional_even/fractional_odd")]

Tessellation pattern

Implicit

[outputtopology("triangle_cw/triangle_ccw/line")]

Output topology

N/A

[patchconstantfunc("FunctionName")]

Function for tessellation factors

Key Conversion Points

  • Split structure: Separate the per-control-point calculations from patch-constant calculations

  • Explicit domain/partitioning: Add required attributes that are implicit in GLSL

  • Patch constants: Create separate function decorated with [patchconstantfunc]

  • Input/Output patches: Use InputPatch<T, N> and return individual control points

Domain Shader (Tessellation Evaluation)

Core Declaration Mapping

GLSL:

// Domain and tessellation mode
layout(triangles, equal_spacing, ccw) in;

void main() {
    // Use gl_TessCoord to interpolate 
    gl_Position = /* position calculation using gl_TessCoord */;
}

Slang:

[shader("domain")]
[domain("tri")]
float4 main(
    PatchTessFactors patchConstants,
    float3 tessCoord : SV_DomainLocation,
    const OutputPatch<ControlPoint, 3> patch
) : SV_Position {
    // Use tessCoord to interpolate
    return /* position calculation using tessCoord */;
}

Key Attribute Mappings

GLSL

Slang

Description

layout(triangles) in

[domain("tri")]

Patch domain type

layout(equal_spacing) in

Set in hull shader

Tessellation spacing

layout(ccw) in

Set in hull shader

Winding order

Key Conversion Points

  • Domain specification: Use [domain("tri/quad/isoline")] attribute

  • Tessellation coordinates: Access via SV_DomainLocation parameter

  • Control points: Access via OutputPatch<T, N> parameter

  • Patch constants: Access via a patch constant struct parameter

Geometry Shader

Core Declaration Mapping

GLSL:

// Set primitive types and max vertices
layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;

void main() {
    // Process and emit vertices
    EmitVertex();
    EndPrimitive();
}

Slang:

[shader("geometry")]
[maxvertexcount(3)]
void main(
    triangle VSOutput input[3], 
    inout TriangleStream<GSOutput> outputStream
) {
    // Process and append vertices
    outputStream.Append(vertex);
    outputStream.RestartStrip();
}

Key Attribute Mappings

GLSL

Slang

Description

layout(points/lines/triangles) in

Input parameter prefix (triangle)

Input primitive type

layout(points/line_strip/triangle_strip) out

Output stream type

Output primitive type

layout(max_vertices = N) out

[maxvertexcount(N)]

Maximum output vertices

Key Conversion Points

  • Declaration: Add [shader("geometry")] and [maxvertexcount(N)]

  • Input primitives: Use primitive type prefix on input array parameter

  • Output primitives: Use appropriate stream type (PointStream, LineStream, TriangleStream)

  • Vertex emission: Replace EmitVertex() with outputStream.Append(v)

  • End primitive: Replace EndPrimitive() with outputStream.RestartStrip()

Amplification Shader (Task Shader)

Core Declaration Mapping

GLSL:

#extension GL_EXT_mesh_shader : require

layout(local_size_x = 32) in;

taskPayloadSharedEXT TaskData payload;

void main() {
    // Set mesh shader dispatch count
    EmitMeshTasksEXT(taskCount, 1, 1, payload);
}

Slang:

[shader("amplification")]
[numthreads(32, 1, 1)]
void main(
    uint gtid : SV_GroupThreadID,
    out payload TaskData payload
) {
    // Set mesh shader dispatch count
    DispatchMesh(taskCount, 1, 1, payload);
}

Key Conversion Points

  • Declaration: Add [shader("amplification")] and [numthreads(X,Y,Z)] decorations

  • Payload: Replace taskPayloadSharedEXT with output parameter

  • Dispatch: Replace EmitMeshTasksEXT with DispatchMesh

  • Thread IDs: Access thread IDs through function parameters with semantics

Mesh Shader

Core Declaration Mapping

GLSL:

#extension GL_EXT_mesh_shader : require

layout(local_size_x = 32) in;
layout(triangles, max_vertices = 64, max_primitives = 126) out;

void main() {
    // Set counts
    SetMeshOutputsEXT(vertexCount, primitiveCount);
    
    // Write vertices and primitives
    gl_MeshVerticesEXT[idx].gl_Position = /* vertex position */;
    gl_PrimitiveTriangleIndicesEXT[idx] = uvec3(a, b, c);
}

Slang:

[shader("mesh")]
[numthreads(32, 1, 1)]
[outputtopology("triangle")]
void main(
    uint gtid : SV_GroupThreadID,
    out vertices MeshVertex verts[64],
    out indices uint3 prims[126]
) {
    // Set counts
    SetMeshOutputCounts(vertexCount, primitiveCount);
    
    // Write vertices and primitives
    verts[idx].position = /* vertex position */;
    prims[idx] = uint3(a, b, c);
}

Key Attribute Mappings

GLSL

Slang

Description

layout(local_size_x = X) in

[numthreads(X, Y, Z)]

Thread group size

layout(triangles) out

[outputtopology("triangle")]

Output primitive type

layout(max_vertices = N, max_primitives = M) out

Output parameters

Maximum vertices/primitives

Key Conversion Points

  • Declaration: Add [shader("mesh")] and [numthreads(X,Y,Z)] decorations

  • Output topology: Use [outputtopology("triangle")] attribute

  • Vertex/primitive count: Replace SetMeshOutputsEXT with SetMeshOutputCounts

  • Vertex access: Replace gl_MeshVerticesEXT[idx] with verts[idx]

  • Primitive access: Replace gl_PrimitiveTriangleIndicesEXT[idx] with prims[idx]

Ray Tracing Shaders

Ray Generation Shader

GLSL:

#extension GL_EXT_ray_tracing : require

layout(location = 0) rayPayloadEXT PayloadData payload;

void main() {
    // Launch rays
    traceRayEXT(tlas, flags, mask, sbtOffset, stride, miss, origin, tMin, direction, tMax, 0);
}

Slang:

[shader("raygeneration")]
void main() {
    RayDesc ray;
    ray.Origin = origin;
    ray.Direction = direction;
    ray.TMin = tMin;
    ray.TMax = tMax;
    
    PayloadData payload;
    TraceRay(tlas, flags, mask, sbtOffset, stride, miss, ray, payload);
}

Closest Hit Shader

GLSL:

#extension GL_EXT_ray_tracing : require

layout(location = 0) rayPayloadInEXT PayloadData payload;

void main() {
    // Process hit
    payload.hit = true;
}

Slang:

[shader("closesthit")]
void main(inout PayloadData payload, in BuiltInTriangleIntersectionAttributes attr) {
    // Process hit
    payload.hit = true;
}

Miss Shader

GLSL:

#extension GL_EXT_ray_tracing : require

layout(location = 0) rayPayloadInEXT PayloadData payload;

void main() {
    // Process miss
    payload.hit = false;
}

Slang:

[shader("miss")]
void main(inout PayloadData payload) {
    // Process miss
    payload.hit = false;
}

Key Conversion Points

  • Declaration: Use appropriate decorator for each shader type

  • Ray payload: Pass as inout parameter instead of global variable

  • Ray tracing: Use TraceRay with a RayDesc struct

  • Built-ins: Access through function calls instead of global variables

  • Hit attributes: Receive via function parameters