• 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
    • Basic Convenience Features
      • Type Inference in Variable Definitions
      • Immutable Values
      • Namespaces
      • Member functions
      • Properties
      • Initializers
      • Operator Overloading
      • Subscript Operator
      • `Optional<T>` type
      • `reinterpret<T>` operation
      • Pointers (limited)
      • `struct` inheritance (limited)
      • Extensions
      • Multi-level break
      • Force inlining
      • Special Scoping Syntax
    • Modules and Access Control
      • Defining a Module
      • Importing a Module
      • Access Control
      • Legacy Modules
    • Capabilities
      • Capability Atoms and Capability Requirements
      • Conflicting Capabilities
      • Requirements in Parent Scope
      • Inferrence of Capability Requirements
      • Inferrence on target_switch
      • Capability Aliases
      • Validation of Capability Requirements
    • Interfaces and Generics
      • Interfaces
      • Generics
      • Supported Constructs in Interface Definitions
      • Associated Types
      • Generic Value Parameters
      • Interface-typed Values
      • Extending a Type with Additional Interface Conformances
      • `is` and `as` Operator
      • Extensions to Interfaces
      • Builtin Interfaces
    • Automatic Differentiation
      • Using Automatic Differentiation in Slang
      • Mathematic Concepts and Terminologies
      • Differentiable Types
      • Forward Derivative Propagation Function
      • Backward Derivative Propagation Function
      • Builtin Differentiable Functions
      • Primal Substitute Functions
      • Working with Mixed Differentiable and Non-Differentiable Code
      • Higher Order Differentiation
      • Interactions with Generics and Interfaces
      • Restrictions of Automatic Differentiation
    • Compiling Code with Slang
      • Concepts
      • Command-Line Compilation with `slangc`
      • Using the Compilation API
      • Multithreading
      • Compiler Options
      • Debugging
    • Using the Reflection API
      • Program Reflection
      • Variable Layouts
      • Type Layouts
      • Arrays
      • Structures
      • Entry Points
    • Supported Compilation Targets
      • Background and Terminology
      • Direct3D 11
      • Direct3D 12
      • Vulkan
      • OpenGL
      • CUDA and OptiX
      • CPU Compute
      • Summary
    • Link-time Specialization and Module Precompilation
      • Link-time Constants
      • Link-time Types
      • Providing Default Settings
      • Restrictions
      • Using Precompiling Modules with the API
      • Additional Remarks
    • Special Topics
      • Handling Matrix Layout Differences on Different Platforms
        • Two conventions of matrix transform math
        • Discussion
        • Matrix Layout
        • Overriding default matrix layout
      • Using Slang to Write PyTorch Kernels
        • Getting Started with slangpy
        • Specializing shaders using slangpy
        • Back-propagating Derivatives through Complex Access Patterns
        • Manually binding kernels
        • Builtin Library Support for PyTorch Interop
        • Type Marshalling Between Slang and Python
      • 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

Uniformity Analysis

On certain hardwares, accessing resources with a non-uniform index may lead to significant performance degradation. Developers can often benefit from a compiler warning for unintentional non-uniform resource access.

Starting from v2024.1.0, Slang provides uniformity analysis that can warn users if a non-dynamically-uniform value is being used unintentionally. This feature is not enabled by default but can be turned on with the -validate-uniformity commandline option when using slangc, or the CompilerOptionName::ValidateUniformity compiler option when using the API.

In addition to specifying the compiler option, the source code must be augmented with the dynamic_uniform modifier to mark function parameters, struct fields or local variables as expecting a dynamic uniform value.

For example, the following code will triger a warning:

// Indicate that the `v` parameter needs to be dynamic uniform.
float f(dynamic_uniform float v)
{
    return v + 1.0;
}

[numthread(1,1,1)]
[shader("compute")]
void main(int tid : SV_DispatchThreadID)
{
    f(tid); // warning: tid is not dynamically uniform.
}

Currently, the analysis is being conservative for struct typed values, in that if any member of the struct is known to be non-uniform, the entire composite is treated as non-uniform:

struct MyType
{
    int a;
    int b;
}

void expectUniform(dynamic_uniform int a){}

void main(int tid : SV_DispatchThreadID)
{
    MyType t;
    t.a = tid;
    t.b = 0;

    // Generates a warning here despite t.b is non-uniform, because
    // t.a is non-uniform and that assignment makes `t` non-uniform.
    expectUniform(t.b);
}

To allow the compiler to provide more accurate analysis, you can use mark struct fields as dynamic_uniform:

struct MyType
{
    int a;
    dynamic_uniform int b;
}

void expectUniform(dynamic_uniform int a){}

void main(int tid : SV_DispatchThreadID)
{
    MyType t;
    t.a = tid;
    t.b = 0;

    // OK, because MyType::b is marked as dynamic_uniform.
    expectUniform(t.b);

    // Warning: trying to assign non-uniform value to dynamic_uniform location.
    t.b = tid;
}

Treat Values as Uniform

In some cases, the compiler might not be able to deduce a value to be non-uniform. If you are certain that a value can be treated as dynamic uniform, you can call asDynamicUniform() function to force the compiler to treat the value as dynamic uniform. For example:

void main(int tid: SV_DispatchThreadID
{
    expectUniform(asDynamicUniform(tid)); // OK.
}

Treat Function Return Values as Non-uniform

The uniformity analysis will automatically propagate uniformity to function return values. However if you have an intrinsic function that does not have a body, or you simply wish the return value of a function to be always treated as non-uniform, you can mark the function with the [NonUniformReturn] attribute:

[NonUniformReturn]
int f() { return 0; }
void expectUniform(dynamic_uniform int x) {}
void main()
{
    expectUniform(f()); // Warning.
}