diff --git a/docs/coming-from-hlsl.md b/docs/coming-from-hlsl.md index 361eecc..2171192 100644 --- a/docs/coming-from-hlsl.md +++ b/docs/coming-from-hlsl.md @@ -75,6 +75,36 @@ int MyFunc() } ``` +#### Variable scope in `for`-loop follows the old FXC rule +The older version of HLSL compiler, FXC, had a little different variable scope for the `for`-loop compared to other languages. + +FXC produces an error or a warning for the following code: +``` +for (int i = 0; i < 4; i++) {...} +for (int i = 0; i < 4; i++) {...} // FXC prints an error or warning +``` + +The warning looks like the following: +``` +my_shader.hlsl(8,14): warning X3078: 'i': loop control variable conflicts with a previous declaration in the outer scope; most recent declaration will be used +``` + +This is no longer the case with the recent HLSL compiler, DXC. But Slang respects the old FXC rule and you may encounter an error like: +``` +error 30200: declaration of 'i' conflicts with existing declaration +``` + +To resolve the problem, you can modify the shader to reuse the previously declared variable: +``` +for (int i = 0; i < 4; i++) {...} +for (i = 0; i < 4; i++) {...} // Reuse the variable declared from the previous for-loop +``` + +Or, you can explicitly set the language to be `slang`: +``` +slangc.exe -lang slang -stage vertex -entry vertexMain my_shader.hlsl +``` + #### Member functions are immutable by default By default, Slang member functions do not allow mutations to `this`. It is as if the member function has the `const` keyword in C/C++. diff --git a/docs/coming-from-hlsl.md.orig b/docs/coming-from-hlsl.md.orig new file mode 100644 index 0000000..9d2c7b1 --- /dev/null +++ b/docs/coming-from-hlsl.md.orig @@ -0,0 +1,383 @@ +--- +title: Migrating to Slang from HLSL +layout: page +description: Migrating to Slang from HLSL +permalink: "/docs/coming-from-hlsl/" +intro_image_absolute: true +intro_image_hide_on_mobile: false +--- + +### Overview +This guide provides a comprehensive overview of the primary syntax and feature differences between HLSL and Slang. It offers essential adjustments needed for a smooth transition and tips to enhance debugging and performance. + +While the languages share similarities, paying close attention to specific syntax and function conventions will ensure a seamless migration of HLSL shaders to Slang. + + +### Key Syntax and Feature Differences + +#### `enum` is scoped in Slang +In HLSL, `enum` is unscoped, which means the enum values can be referred to without the enum's name. +In Slang, `enum` is scoped, requiring explicit reference to the enum's name along with its values. + + + +
HLSL shaderSlang shader
+{% capture somemarkdown %} +```hlsl +enum MyEnum +{ + MyEnum_A, + MyEnum_B, + MyEnum_C +}; + +int MyFunc() +{ + return int(MyEnum_A); +} +``` +{% endcapture %} +{{ somemarkdown | markdownify }} + + {% capture somemarkdown %} + +```hlsl +enum MyEnum +{ + A, + B, + C +}; + +int MyFunc() +{ + return int(MyEnum::A); +} +``` +{% endcapture %} +{{ somemarkdown | markdownify }} +
+ +To make `enum` unscoped in Slang, use the `-unscoped-enums` option or add the `[UnscopedEnum]` attribute to explicitly declare an enum as unscoped. +```hlsl +// Slang shader +[UnscopedEnum] +enum MyEnum +{ + MyEnum_A, + MyEnum_B, + MyEnum_C +}; + +int MyFunc() +{ + return int(MyEnum_A); +} +``` + + +<<<<<<< HEAD +#### Member functions are immutable by default +======= +### Variable scope in `for`-loop follows the old FXC rule +The older version of HLSL compiler, FXC, had a little different variable scope for the `for`-loop compared to other languages. + +FXC produces an error or a warning for the following code: +``` +for (int i = 0; i < 4; i++) {...} +for (int i = 0; i < 4; i++) {...} +``` + +The warning looks like the following: +``` +my_shader.hlsl(8,14): warning X3078: 'i': loop control variable conflicts with a previous declaration in the outer scope; most recent declaration will be used +``` + +This is no longer the case with the recent HLSL compiler, DXC. But Slang respects the old FXC rule and you may encounter an error like: +``` +error 30200: declaration of 'i' conflicts with existing declaration +``` + +To resolve the problem, you can modify the shader to reuse the previously declared variable: +``` +for (int i = 0; i < 4; i++) {...} +for (i = 0; i < 4; i++) {...} // Reuse the variable declared from the previous for-loop +``` + +Or, you can explicitly set the language to be `slang`: +``` +slangc.exe -lang slang -stage vertex -entry vertexMain my_shader.hlsl +``` + + +### Member functions are immutable by default +>>>>>>> 90589ae (Add a new section that explains the variable scope problem with for-loop) +By default, Slang member functions do not allow mutations to `this`. It is as if the member function has the `const` keyword in C/C++. + +To mutate `this`, you must explicitly use the `[mutating]` attribute on each function. + +This is a significant departure from HLSL, but the compiler will flag any missing keywords with an error. + + +
HLSL shaderSlang shader
+{% capture somemarkdown %} +```hlsl +struct Counter +{ + int count; + void increment() { count++; } +}; +``` +{% endcapture %} +{{ somemarkdown | markdownify }} + +{% capture somemarkdown %} +```hlsl +struct Counter +{ + int count; + + [mutating] + void increment() { count++; } +}; +``` +{% endcapture %} +{{ somemarkdown | markdownify }} +
+ + +#### Forward declaration is not needed and not supported +In Slang, function declarations do not need to precede their usage. + +Furthermore, Slang does not support separating the declaration from its definition for member functions. Member functions must be fully defined at the point of declaration. + + +#### Generics Instead of Templates +Slang does not support a "template" feature like HLSL does. +If your HLSL shaders use templates, they will need to be converted to use generics. +Depending on the complexity, this conversion process is generally straightforward. + +When the template argument is a constant integer value, use the `let XX : uint` or `uint XX` syntax as shown below, + + +
HLSL shaderSlang shader
+{% capture somemarkdown %} +```hlsl +template +uint GetValue(const uint index) +{ + return index % strideX, index / strideY; +} +``` +{% endcapture %} +{{ somemarkdown | markdownify }} + +{% capture somemarkdown %} + +```hlsl +__generic +uint GetValue(const uint index) +{ + return index % strideX, index / strideY; +} +``` +{% endcapture %} +{{ somemarkdown | markdownify }} +
+ +When the template argument is a typename, you must use a built-in interface or a custom interface you define. + + +
HLSL shaderSlang shader
+{% capture somemarkdown %} + +```hlsl +template +T max4(T x, T y, T z, T w) +{ + return max(max(x, y), max(z, w)); +} +``` +{% endcapture %} +{{ somemarkdown | markdownify }} + +{% capture somemarkdown %} +```hlsl +__generic // `typename` can be omitted +T max4(T x, T y, T z, T w) + where T : __BuiltinFloatingPointType +{ + return max(max(x, y), max(z, w)); +} +``` +{% endcapture %} +{{ somemarkdown | markdownify }} +
+ +For more detailed explanations on defining a custom interface, please refer to the [Slang User's Guide](https://shader-slang.com/slang/user-guide/interfaces-generics.html). + + +#### `#pragma` for DXC wouldn't work for Slang + +If your HLSL shaders use `#pragma` for the DXC compiler, these will not be compatible with Slang. +You will need to remove these lines or encapsulate them as follows, +```hlsl +#if !COMPILER_SLANG +// Generate vector truncation warnings to errors. +#pragma warning(error: 3206) +#endif // #if !COMPILER_SLANG +``` + + +#### Operator Overloading +Slang supports operator overloading, but it cannot be defined as a member method. + + + +
HLSL shaderSlang shader
+{% capture somemarkdown %} + +```hlsl +struct MyStruct +{ + MyStruct operator+(MyStruct rhs) + { + MyStruct tmp; + tmp.value = value + rhs.value; + return tmp; + } + + float value; +}; +``` +{% endcapture %} +{{ somemarkdown | markdownify }} + +{% capture somemarkdown %} + +```hlsl +struct MyStruct +{ + MyStruct operator_ADD(MyStruct rhs) + { + MyStruct tmp; + tmp.value = value + rhs.value; + return tmp; + } + + float value; +}; + +MyStruct operator+(MyStruct lhs, MyStruct rhs) +{ + return lhs.operator_ADD(rhs); +} +``` +{% endcapture %} +{{ somemarkdown | markdownify }} +
+ +For more details, please consult the [Slang User's Guide](https://shader-slang.com/slang/user-guide/convenience-features.html#operator-overloading) + +#### Subscript Operator +Slang uses a different syntax for overloading subscript operator so both reads and writes to a subscript location can be defined. + + +
HLSL shaderSlang shader
+{% capture somemarkdown %} + +```hlsl +struct MyType +{ + float values[12]; + + float operator[](int index) + { + return values[index]; + } +} +``` +{% endcapture %} +{{ somemarkdown | markdownify }} + +{% capture somemarkdown %} + +```hlsl +struct MyType +{ + float values[12]; + + __subscript(int index) -> float + { + get { return val[index]; } + set { val[index] = newValue; } + } +} +``` +{% endcapture %} +{{ somemarkdown | markdownify }} +
+ +For more details, please consult the [Slang User's Guide](https://shader-slang.com/slang/user-guide/convenience-features.html#subscript-operator). + + +#### Implicit parameter binding +Slang binds resources based on the shader before Dead-Code-Elimination. This means that even if a uniform parameter is not utilized by the shader, Slang will still assign a resource binding index to it. + +This differs from HLSL's behavior, where the DXC compiler removes unused parameters from the compiled shaders. The DXC reflection API then provides information on which parameters are actually being used. + +This approach ensures consistent behavior across different variations of the same shader, as Slang does not remove unused parameters during its linking process, maintaining a consistent set of parameters regardless of how the shader was used or linked. + + +#### `unsigned int` is not supported +Slang does not support type names that use more than one token. As a result, `unsigned int` or `signed int` are not supported. These should be renamed to `uint` or `int` respectively. + + +#### Buffer Layouts +Slang defaults to std140 for constant buffers and std430 for structured buffers and related. + - Use `-fvk-use-scalar-layout` to set buffer layout to scalar block layout. + - Use `-fvk-use-gl-layout` to set std430 layout for raw buffer load/stores + +StructuredBuffer and related objects can also take a per resource layout +```hlsl + +StructuredBuffer +StructuredBuffer +StructuredBuffer + +``` + + +#### `#pragma pack_matrix()` is not supported +HLSL provides a way to change the matrix packing order with a pragma. + +While Slang doesn't support the same pragma syntax, you can achieve the same functionality with `-matrix-layout-column-major` or `-matrix-layout-row-major`. + + +#### Slang requires more strict type casting +Slang demands more strict type casting, but you can add your own casting functions if needed. +Due to this difference, some casting issues may appear as errors while migrating your HLSL shaders to Slang. + + +#### SPIR-V target specific functionalities +When you target SPIR-V, there are a few things that the user may want to know. Please check the [Slang User's Guide](https://shader-slang.com/slang/user-guide/spirv-target-specific.html) for more details. + + +### Debugging and Performance Tips + +When debugging Slang shaders, disabling optimizations can simplify the debugging process. Use -O0 during development, and consider experimenting with [ForceInline] to reduce compile times for performance-critical shaders. + + +#### `#line` directives +Slang offers a command-line option to emit or suppress `#line` directives when targeting C-like text formats such as HLSL, GLSL, Metal, and WGSL. +When `#line` directives are emitted, they can assist in debugging with shader debugging tools, as these tools can correlate back to the original Slang shader. + +For more information, please refer to `LineDirectiveMode` in the [Slang User's Guide](https://shader-slang.com/slang/user-guide/compiling.html). + + +#### Experiment with [ForceInline] +`[ForceInline]` is akin to the `inline` keyword in C++, where the body of a function is inlined at the call locations. This typically does not make any observable differences, but we have noticed that using `[ForceInline]` can reduce compile times compared to HLSL compilation with DXC. + +This is because the shader optimization step inside DXC involves additional processes to optimize out the `out` or `inout` modifiers. When the function is inlined, these modifiers become redundant, thus reducing compile times. + +This characteristic may change in the future, but it is worth experimenting with `[ForceInline]`.