From 0befc84fddeea5715bf25697fd119a70a7124338 Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Fri, 12 Feb 2021 12:53:56 -0800 Subject: Further documentation work (#1703) * Move around the conventional/convenience features chapters * Add a first draft of a section on compilation using `slangc` and the COM-lite API Co-authored-by: Yong He --- docs/user-guide/02-convenience-features.md | 227 ----------- docs/user-guide/02-conventional-features.md | 579 ++++++++++++++++++++++++++++ docs/user-guide/03-convenience-features.md | 274 +++++++++++++ docs/user-guide/03-conventional-features.md | 579 ---------------------------- docs/user-guide/05-compiling.md | 493 +++++++++++++++++++++++ 5 files changed, 1346 insertions(+), 806 deletions(-) delete mode 100644 docs/user-guide/02-convenience-features.md create mode 100644 docs/user-guide/02-conventional-features.md create mode 100644 docs/user-guide/03-convenience-features.md delete mode 100644 docs/user-guide/03-conventional-features.md create mode 100644 docs/user-guide/05-compiling.md diff --git a/docs/user-guide/02-convenience-features.md b/docs/user-guide/02-convenience-features.md deleted file mode 100644 index 63793a870..000000000 --- a/docs/user-guide/02-convenience-features.md +++ /dev/null @@ -1,227 +0,0 @@ -# Basic Convenience Features - -This topic covers a series of nice-to-have language features in Slang. These features are not supported by HLSL but are introduced to Slang to simplify code development. Many of these features are added to Slang per request of our users. - -## Member functions - -Slang supports defining member functions in `struct`s. For example, it is allowed to write: - -```hlsl -struct Foo -{ - int compute(int a, int b) - { - return a + b; - } -} -``` - -You can use the `.` syntax to invoke member functions: - -```hlsl -Foo foo; -int rs = foo.compute(1,2); -``` - -Slang also supports static member functions, For example: -``` -struct Foo -{ - static int staticMethod(int a, int b) - { - return a + b; - } -} -``` - -Static member functions are accessed the same way as other static members, via either the type name or an instance of the type: - -```hlsl -int rs = Foo.staticMethod(a, b); -``` - -or - -```hlsl -Foo foo; -... -int rs = foo.staticMethod(a,b); -``` - -### Mutability of member function - -For GPU performance considerations, the `this` argument in a member function is immutable by default. If you modify the content in `this` argument, the modification will be discarded after the call and does not affect the input object. If you intend to define a member function that mutates the object, use `[mutating]` attribute on the member function as shown in the following example. - -```hlsl -struct Foo -{ - int count; - - [mutating] - void setCount(int x) { count = x; } - - void setCount2(int x) { count = x; } -} - -void test() -{ - Foo f; - f.setCount(1); // f.count is 1 after the call. - f.setCount2(2); // f.count is still 1 after the call. -} -``` - -## Properties - -Properties provide a convienient way to access values exposed by a type, where the logic behind accessing the value is defined in `getter` and `setter` function pairs. Slang's `property` feature is similar to C# and Swift. -```C# -struct MyType -{ - uint flag; - - property uint highBits - { - get { return flag >> 16; } - set { flag = (flag & 0xFF) + (newValue << 16); } - } -}; -``` - -Or equivalently in a "modern" syntax: - -```C# -struct MyType -{ - uint flag; - - property highBits : uint - { - get { return flag >> 16; } - set { flag = (flag & 0xFF) + (newValue << 16); } - } -}; -``` - -You may also use an explicit parameter for the setter method: -```C# -property uint highBits -{ - set(uint x) { flag = (flag & 0xFF) + (x << 16); } -} -``` - -> #### Note #### -> Slang currently does not support automatically synthesized `getter` and `setter` methods. For example, -> the following code is not supported: -> ``` -> property uint highBits {get;set;} // Not supported yet. -> ``` - -## Initializers -> #### Note #### -> The syntax for defining initializers are subject to future change. - - -Slang supports defining initializers in `struct` types. You can write: -```C# -struct MyType -{ - int myVal; - __init(int a, int b) - { - myVal = a + b; - } -} -``` - -You can use an initializer to construct a new instance by using the type name in a function call expression: -```C# -MyType instance = MyType(1,2); // instance.myVal is 3. -``` - -You may also use C++ style initializer list to invoke an initializer: -```C# -MyType instance = {1, 2}; -``` - -If an initializer does not define any parameters, it will be recognized as *default* initializer that will be automatically called at the definition of a variable: - -```C# -struct MyType -{ - int myVal; - __init(i) - { - myVal = 10; - } -}; - -int test() -{ - MyType test; - return test.myVal; // returns 10. -} -``` - -## Operator Overloading - -Slang allows defining operator overloads as global methods: -```C# -struct MyType -{ - int val; - __init(int x) { val = x; } -} - -MyType operator+(MyType a, MyType b) -{ - return MyType(a.val + b.val); -} - -int test() -{ - MyType rs = MyType(1) + MyType(2); - return rs.val; // returns 3. -} -``` - -Slang currently supports overloading the following operators: `+`, `-`, `*`, `/`, `%`, `&`, `&&`, `|`, `||`, `<`, `>`, `<=`, `>=`, `==`, `!=`, unary `-`, `~` and `!`. - -## `struct` inheritance (limited) - -Slang supports a limited form of inheritance. A derived `struct` type has all the members defined in the base type it is inherited from: - -```C# -struct Base -{ - int a; - void method() {} -} - -struct Derived : Base { int b; } - -void test() -{ - Derived c; - c.a = 1; // OK, a is inherited from `Base`. - c.b = 2; - c.method(); // OK, `method` is inherited from `Base`. -} -``` - -A derived type can be implicitly casted to its base type: -```C# -void acceptBase(Base b) { ... } -void test() -{ - Derived c; - acceptBase(c); // OK, c is implicitly casted to `Base`. -} -``` - -Slang supports controlling whether a type can be inherited from with `[sealed]` and `[open]` attributes on types. -If a base type is marked as `[sealed]`, then inheritance from the type is not allowed anywhere outside the same module (file) that is defining the base type. If a base type is marked as `[open]`, then inheritance is allowed regardless of the location of the derived type. By default, a type is `[sealed]` if no attributes are declared, which means the type can only be inherited by other types in the same module. - -### Limitations - -Please note that the support for inheritance is currently very limited. Common features that comes with inheritance, such as `virtual` functions and multiple inheritance are not supported by the Slang compiler. Implicit down-casting to the base type and use the result as a `mutable` argument in a function call is also not supported. diff --git a/docs/user-guide/02-conventional-features.md b/docs/user-guide/02-conventional-features.md new file mode 100644 index 000000000..8f05c2466 --- /dev/null +++ b/docs/user-guide/02-conventional-features.md @@ -0,0 +1,579 @@ +Conventional Language Features +============================== + +Many of the language concepts in Slang are similar to those in other real-time shading languages like HLSL and GLSL, and also to general-purpose programming languages in the "C family." +This chapter covers those parts of the Slang language that are _conventional_ and thus unlikley to surprise users who are already familiar with other shading languages, or languages in the C family. + +Readers who are comfortable with HLSL variables, types, functions, statements, as well as concentions for shader parameters and entry points may prefer to skip this chapter. +Readers who are not familiar with HLSL, but who are comfortable with GLSL and/or C/C++, may want to carefully read the sections on types, expressions, shader parameters, and entry points while skimming the others. + +Types +----- + +Slang supports conventional shading language types including scalars, vectors, matrices, arrays, structures, enumerations, and resources. + +> #### Note #### +> Slang does not currently support pointer types as in C/C++. +> Pointers cannot be implemented robustly and completely on many of the target platforms Slang currently supports. + +### Scalar Types + +#### Integer Types + +The following integer types are provided: + +| Name | Description | +|---------------|-------------| +| `int8_t` | 8-bit signed integer | +| `int16_t` | 16-bit signed integer | +| `int` | 32-bit signed integer | +| `int64_t` | 64-bit signed integer | +| `uint8_t` | 8-bit unsigned integer | +| `uint16_t` | 16-bit unsigned integer | +| `uint` | 32-bit unsigned integer | +| `uint64_t` | 64-bit unsigned integer | + +All targets support the 32-bit `int` and `uint` types, but support for the other types depends on the capabilities of each target platform. + +Integer literals can be both decimal and hexidecimal, and default to the `int` type. +A literal can be explicitly made unsigned with a `u` suffix. + +The following floating-point type are provided: + +| Name | Description | +|---------------|------------------------------| +| `half` | 16-bit floating-point number | +| `float` | 32-bit floating-point number | +| `double` | 64-bit floating-point number | + +All targets support the 32-bit `float`, but support for the other types depends on the capabilities of each target platform. + +### Boolean Type + +The type `bool` is used to represent Boolean truth value: `true` and `false`. + +#### The Void Type + +The type `void` is used as a placeholder to represent the result type of functions that don't return anything. + +### Vector Types + +Vector types can be written as `vector` where `T` is a scalar type and `N` is an integer from 2 to 4 (inclusive). +The type `vector` is a vector of `N` _elements_ (also called _components_) each of type `T`. + +As a convenience, pre-defined vector types exist for each scalar type and valid element count, with a name using the formula `<><>`. +For example, `float3` is a convient name for `vector`. + +### Matrix Types + +Matrix types can be written as `matrix` where `T` is a scalar type and both `R` and `C` are integers from 2 to 4 (inclusive). +The type `matrix` is a matrix with _elements_ of type `T`, and comprising `R` rows and `C` columns. + +As a convenience, pre-defined matrix types exist for each scalar type and valid row/column count, with a name using the formula `<><>x<>`. +For example, a `float3x4` is a convient name for `matrix`. + +> #### Note #### +> Readers familiar with GLSL should be aware that a Slang `float3x4` represents a matrix with three rows and four columns, while a GLSL `mat3x4` represents a matrix with three *columns* and four *rows*. +> In most cases, this difference is immaterial because the subscript expression `m[i]` returns a `float4` (`vec4`) in either language. +> For now it is enough to be aware that there is a difference in convention between Slang/HLSL/D3D and GLSL/OpenGL. + +### Array Types + +An array type `T[N]` represents an array of `N` elements of type `T`. +When declaring a variable with an array type, the `[]` brackets come after the variable name, following the C convention for variable declarations: + +```hlsl +// the type of `a` is `int[3]` +int a[3]; +``` + +Sometimes a value with an array type can be declared without an explicit element count. +In some cases the element count is then inferred from the initial value of a variable: + +```hlsl +// the type of `a` is `int[3]` +int a[] = { 1, 2, 3 }; +``` + +In other cases, the result is a _runtime-sized_ array, where the actual element count will be determined later: + +```hlsl +// the type of `b` is `int[]` +void f( int b[] ) +{ ... } +``` + +There are more limits on how runtime-sized arrays can be used than on arrays of statically-known element count. + +> #### Note #### +> In Slang arrays are _value types_, meaning that assignment, parameter passing, etc. semantically copy values of array type. +> In some languages -- notably C, C++, C#, and Java -- assignment and parameter passing for treat arrays as _reference types_, +> meaning that these operations assign/pass a reference to the same underlying storage. + +### Structure Types + +Structure types can be introduced with the `struct` keyword, as in most C-family languages: + +```hlsl +struct MyData +{ + int a; + float b; +} +``` + +> #### Note #### +> Unlike C, and like most other C-family languages, the `struct` keyword in Slang introduces a type directly, and there is no need to combine it with a `typedef`. + +> #### Note #### +> Slang allows for a trailing semicolon (`;`) on `struct` declarations, but does not require it. + +### Enumeration Types + +Enumeration types can be introduced with the `enum` keyword to provide type-safe constants for a range of values: + +```hlsl +enum Channel +{ + Red, + Green, + Blue +} +``` + +> #### Note #### +> Unlike C/C++, `enum` types in Slang are always scoped (like `enum class` in C++). You can write `enum class` in Slang if it makes you happy, but it isn't required. + +### Opaque Types + +The Slang standard library defines a large number of _opaque_ types which provide access to objects that are allocated via GPU APIs. + +What all opaque types have in common is that they are not "first-class" types on most platforms. +Opaque types (and structure or array types that contain them) may be limited in the following ways (depending on the platform): + +* Functions that return opaque types may not be allowed +* Global and `static` variables that use opaque types may not be allowed +* Opaque types may not appear in the element types of buffers, except where explicitly noted as allowed + +#### Texture Types + +Texture types -- including `Texure2D`, `TextureCubeArray`, `RWTexture2D`, and more -- are used to access formatted data for read, write, and sampling operations. +Textures can be used to represent simple images, but also support _mipmapping_ as a way to reduce noise when sampling at lower than full resolution. +The full space of texture types follows the formula: + + <>Texture<><><><> + +where: + +* The _access_ can be read-only (no prefix), read-write (`RW`), or read-write with a guarantee of rasterization order for operations on the given resource (`RasterizerOrdered`). +* The _base shape_ can be `1D`, `2D`, `3D`, or `Cube`. +* The _multisample-ness_ can non-multiple-sample, or multi-sampled (`MS`). +* The _array-ness_ can either be non-arrayed, or arrayed (`Array`). +* The _element type_ can either be explicitly specified (``) or left as the default of `float4` + +Not all combinations of these options are supported, and some combinations may be unsupported on some targets. + +#### Sampler + +Sampler types encapsulate parameters that control addressing and filtering for texture-sampling operations. +There are two sampler types: `SamplerState` and `SamplerComparisonState`. +`SamplerState` is applicable to most texture sampling operations, while `SamplerComparisonState` is used for "shadow" texture sampling operations which compare texels to a reference value before filtering. + +> #### Note #### +> Some target platforms and graphics APIs do not support separation of textures and sampling state into distinct types in shader code. +> On these platforms the Slang texture types include their own sampling state, and the sampler types are placeholder types that carry no data. + +#### Buffers + +There are multiple buffer types supported by modern graphics APIs, with substantially different semantics. + +##### Formatted Buffers + +Formatted buffers (sometimes referred to as "typed buffers" or "buffer textures") are similar to 1D textures (in that they support format conversion on loads), without support for mipmapping. +The formula for formatted buffer types is: + + <>Buffer<><> + +Where the _access_, _array-ness_, and _element type_ are the same as for textures, with the difference that _element type_ is not optional. + +A buffer type like `Buffer` represents a GPU resource that stores one or more values that may be fetched as a `float4` (but might internally be stored in another format, like RGBA8). + +##### Flat Buffers + +Flat buffers differ from formatted buffers in that they do not support format conversion. +Flat buffers are either _structured_ buffers or _byte-addressed_ buffers. + +Structured buffer types like `StructuredBuffer` include an explicit element type `T` that will be loaded and stored from the buffer. +Byte-addressed buffer types like `ByteAddressBuffer` do not specify any particular element type, and instead allow for values to be loaded or stored from any (suitably aligned) byte offset in the buffer. +Both structured and byte-addressed bufers can use an _access_ to distinguish between read-only and read-write usage. + +##### Constant Buffers + +Constant buffers (sometimes also called "uniform buffers") are typically used to pass immutable parameter data from a host application to GPU code. +The constant buffer type `ConstantBuffer` includes an explicit element type. +Unlike formatted or flat buffers, a constant buffer conceptualy contains only a *single* value of its element type, rather than one or more values. + +Expressions +----------- + +Slang supports the following expression forms with nearly identical syntax to HLSL, GLSL, and C/C++: + +* Literals: `123`, `4.56`, `false` + +> #### Note #### +> Unlike C/C++, but like HLSL/GLSL, an unsuffixed floating-point literal has the `float` type in Slang, rather than `double` + +* Member lookup: `structValue.someField`, `MyEnumType.FirstCase` + +* Function calls: `sin(a)` + +* Vector/matrix initialization: `int4(1, 2, 3, 4)` + +* Casts: `(int) x`, `double(0.0)` + +* Subscript (indexing): `a[i]` + +* Initializer lists: `int b[] = { 1, 2, 3 };` + +* Assignment: `l = r` + +* Operators: `-a`, `b + c`, `d++`, `e %= f` + +> #### Note #### +> Like HLSL but unlike most other C-family languages, the operators `&&` and `||`, along with the conditional operator `?:` do *not* currently perform "short-circuiting"; +> they evaluate all of their operands unconditionally. +> The default behavior of these operators is likely to change in a future Slang release. + +Additional expression forms specific to shading languages follow. + +### Operators on Vectors and Matrices + +The ordinary unary and binary operators can also be applied to vectors and matrices, where they apply element-wise. + +> #### Note #### +> In GLSL, most operators apply component-wise to vectors and matrices, but the multiplication operator `*` computes the traditional linear-algebraic product of two matrices, or a matrix and a vector. +> Where a GLSL programmer would write `m * v` to multiply a `vec3x4` by a `vec3`, a Slang programmer should write `mul(v,m)` to multiply a `float3` by a `float3x4`. +> In this example, the order of operands is reversed to account for the difference in row/column conventions. + +### Swizzles + +Given a value of vector type, a _swizzle_ expression extracts one or more of the elements of the vector to produce a new vector. +For example, if `v` is a vector of type `float4`, then `v.xy` is a `float2` consisting of the `x` and `y` elements of `v`. +Swizzles can reorder elements (`v.yx`) or include duplicate elements (`v.yyy`). + +> #### Note #### +> Unlike GLSL, Slang only supports `xyzw` and `rgba` as swizzle elements, and not the seldom-used `stpq`. + +> #### Note #### +> Unlike HLSL, Slang does not currently support matrix swizzle syntax. + +Statements +---------- + +Slang supports the following statement forms with nearly identical syntax to HLSL, GLSL, and C/C++: + +* Expression statements: `f(a, 3);`, `a = b * c;` + +* Local variable declarations: `int x = 99;` + +* Blocks: `{ ... }` + +* Empty statement: `;` + +* `if` statements + +* `switch` statements + +> #### Note #### +> Unlike C/C++, `case` and `default` statements must be directly nested under a `switch`, rather than being allowed under nested control flow (Duff's Device and similar idioms are not allowed). +> In addition, while multiple `case`s can be grouped together, all other forms of "fallthrough" are unsupported. + +* `for` statements + +* `while` statements + +* `do`-`while` statements + +* `break` statements + +* `continue` statements + +* `return` statements + +> #### Note #### +> Slang does not support the C/C++ `goto` keyword. + +> #### Note #### +> Slang does not support the C++ `throw` keyword. + +Additional statement forms specific to shading languages follow. + +### Discard Statements + +A `discard` statement can be used in the context of a fragment shader to terminate shader execution for the current fragment, and to cause the graphics system to discard the corresponding fragment. + +Functions +--------- + +Slang supports function definitions with traditional C syntax: + +```hlsl +float addSomeThings(int x, float y) +{ + return x + y; +} +``` + +Slang supports overloading of functions based on parameter types. + +Function parameters may be marked with a _direction_ qualifier: + +* `in` (the default) indicates a by-value input parameter +* `out` indicates an output parameter +* `inout` or `in out` indicates an input/output parameter + +> #### Note #### +> The `out` and `inout` directions are superficially similar to non-`const` reference parameters in C++. +> In cases that do not involve aliasing of mutable memory, the semantics should be equivalent. + +Preprocessor +------------ + +Slang supports a C-style preprocessor with the following directives; + +* `#include` +* `#define` +* `#undef` +* `#if`, `#ifdef`, `#ifndef` +* `#else`, `#elif` +* `#endif` +* `#error` +* `#warning` +* `#line` +* `#pragma`, including `#pragma once` + +> #### Note #### +> Variadic macros are not currently supported by the Slang preprocessor. + +Attributes +---------- + +_Attributes_ are a general syntax for decorating declarations and statements with additional semantic information or meta-data. +Attributes are surrounded with square brackets (`[]`) and prefix the declaration or statement they apply to. + +For example, an attribute can indicate the programmer's desire that a loop be unrolled as much as possible: + +```hlsl +[unroll] +for(int i = 0; i < n; i++) +{ /* ... */ } +``` + +> #### Note #### +> Traditionally, all attributes in HLSL used a single layer of `[]` brackets, matching C#. +> Later, C++ borrowed the idea from C# but used two layers of brackets (`[[]]`). +> Some recent extensions to HLSL have used the C++-style double brackets instead of the existing single brackets syntax. +> Slang tries to support both alternatives uniformly. + +Global Variables and Shader Parameters +-------------------------------------- + +By default, global-scope variable declarations in Slang represent _shader parameters_ passed from host application code into GPU code. +Programmers must explicitly mark a global-scope variable with `static` for it to be treated as a shader parameter, even if the variable is marked `const`: + +```hlsl +// a shader parameter: +float a; + +// also a shader parameter (despite `const`): +const int b = 2; + +// a "thread-local" global variable +static int c = 3; + +// a compile-time constant +static const int d = 4; +``` + +### Global Constants + +A global-scope `static const` variable defines a compile-time constant for use in shader code. + +### Global-Scope Static Variables + +A non-`const` global-scope `static` variable is conceptually similar to a global variable in C/C++, with the key difference that it has distinct storage per *thread* rather than being truly global. +Each logical thread of shader execution initiated by the GPU will be allocated fresh storage for these `static` variables, and values written to those variables will be lost when a shader thread terminates. + +> #### Note #### +> Some target platforms do not support `static` global variables in all use cases. +> Support for `static` global variables should be seen as a legacy feature, and further use is discouraged. + +### Global Shader Parameters + +Global shader parameters may use any type, including both opaque and non-opaque types: + +```hlsl +ConstantBufer c; +Texture2D t; +float4 color; +``` + +To avoid confusion, the Slang compiler will warn on any global shader parameter that includes non-opaque types, because it is likely that a user thought they were declaring a global constant or a traditional global variable. +This warning may be suppressed by marking the parameter as `uniform`: + +```hlsl +// WARNING: this declares a global shader parameter, not a global variable +int gCounter = 0; + +// OK: +uniform float scaleFactor; +``` + +#### Legacy Constant Buffer Syntax + +For compatibility with existing HLSL code, Slang also supports global-scope `cbuffer` declarations to introduce constant buffers: + +```hlsl +cbuffer PerFrameCB +{ + float4x4 mvp; + float4 skyColor; + // ... +} +``` + +A `cbuffer` declaration like this is semantically equivalent to a shader parameter declared using the `ConstantBuffer` type: + +```hlsl +struct PerFrameData +{ + float4x4 mvp; + float4 skyColor; + // ... +} +ConstantBuffer PerFrameCB; +``` + +#### Explicit Binding Markup + +For compatibility with existing codebases, Slang supports pre-existing markup syntax for associating shader parameters of opaque types with binding information for specific APIs. + +Binding information for Direct3D platforms may be specified using `register` syntax: + +```hlsl +Texture2D a : register(t0); +Texture2D b : register(t1, space0); +``` + +Binding information for Vulkan (and OpenGL) may be specified using `[[vk::binding(...)]]` attributes + +```hlsl +[[vk::binding(0)]] +Texture2D a; + +[[vk::binding(1, 0)]] +Texture2D b; +``` + +A single parameter may use both the D3D-style and Vulkan-style markup, but in each case explicit binding markup only applies to the API family for which it was designed. + +> #### Note #### +> Explicit binding markup is tedious to write and error-prone to maintain. +> It is almost never required in Slang codebases. +> The Slang compiler can automatically synthesize bindings in a completely deterministic fashion and in most cases the bindings it generates are the as what a programmer would have written manually. + +Shader Entry Points +------------------- + +An _entry point_ is a function that can be used as the starting point for execution of a GPU thread. + +Here is an example of an entry-point function in Slang: + +```hlsl +[shader("vertex")] +float4 vertexMain( + float3 modelPosition : POSITION, + uint vertexID : SV_VertexID, + uniform float4x4 mvp) + : SV_Position +{ /* ... */ } +``` + +In the following sections we will use this example to explain important facets of entry point declarations in Slang. + +### Entry Point Attribute and Stages + +The `[shader(...)]` attribute is used to mark a function in Slang as a shader entry point, and also to specify which pipeline stage it is meant for. +In this example, the `vertexMain` shader indicates that it is meant for the `vertex` stage of the traditional rasterization pipeline. +Rasterization, compute, and ray-tracing pipelines each define their own stages, and new versions of graphics APIs may introduce new stages. + +For compatibility with legacy codebases, Slang supports code that leaves off `[shader(...)]` attributes; in these cases application developers must specify the names and stages for their entry points via explicit command-line or API options. +It is recommended that new codebases always use `[shader(...)]` attributes both to simplify their workflow, and to make code more explicit and "self-documenting." + +> #### Note #### +> In GLSL, a file of shader code may only include one entry point, and all code `#include`d into that file must be compatible with the stage of that entry point. By default, GLSL requires that an entry point be called `main`. +> Slang allows for multiple entry points to appear in a file, for any combination of stage, and with any valid identifier as a name. + +### Parameters + +The parameter of an entry-point function represent either _varying_ or _uniform_ inputs. +Varying inputs are those that may vary over threads invoked as part of the same batch (a draw call, compute dispatch, etc.), while uniform inputs are those that are guaranteed to be the same for all threads in a batch. +Entry-point parameters in Slang default to varying, but may be explicitly marked `uniform`. + +If an entry-point function declares a non-`void` result type, then its result behaves like an anonymous `out` parameter that is varying. + +### Binding Semantics + +The varying parameters of an entry point must declare a _binding semantic_ to indicate how those parameters should be connected to the execution environment. +A binding semantic for a parameter may be introduced by suffixing the variable name with a colon (`:`) and an identifier for the chosen binding semantic. +A binding semantic for a function result is introduced similarly, but comes after the parameter list. + +It is not shown in this example, but binding semantics may also be applied to individual `struct` fields, in cases where a varying parameter of `struct` type is used. + +#### System-Defined Binding Semantics + +In the `vertexMain` entry point, the `vertexID` parameter uses the `SV_VertexID` binding semantic, which is a _system-defined_ binding semantic. +Standard system-defined semantics are distinguished by the `SV_` prefix. + +A system-defined binding semantic on an input parameter indicates that the parameter should receive specific data from the GPU as defined by the pipeline and stage being used. +For example, in a vertex shader the `SV_VertexID` binding semantic on an input yields the ID of the particular vertex being processed on the current thread. + +A system-defined binding semantic on an ouptput parameter or function result indicates that when a shader thread returns from the entry point the value stored in that output should be used by the GPU in a specific way defined by the pipeline and stage being used. +For example, in a vertex shader the `SV_Position` binding semantic on an output indicates that it represents a clip-space position that should be communicated to the rasterizer. + +The set of allowed system-defined binding semantics for inputs and outputs depends on the pipeline and stage of an entry point. +Some system-defined binding semantics may only be available on specific targets or specific versions of those targets. + +> #### Note #### +> Instead of using ordinary function parameters with system-defined binding semantics, GLSL uses special system-defined global variables with the `gl_` name prefix. +> Some recent HLSL features has introduced special globally-defined functions that behave similarly to these `gl_` globals. + +#### User-Defined Binding Semantics + +In the `vertexMain` entry point, the `modelPosition` parameter used the `POSITION` binding semantic, which is a _user-defined_ binding semantic. + +A user-defined binding semantic on an input indicates that the parameter should receive data with a matching binding semantic from a preceding stage. +A user-defined binding semantic on an output indicates that the parameter should provide data to a parameter with a matching binding semantic in a following stage. + +Whether or not inputs and outputs with user-defined binding semantics are allowed depends on the pipeline and stage of an entry point. + +Different APIs and different stages within the same API may match up entry point inputs/outputs with user-defined binding semantics in one of two ways: + +* By-index matching: user-defined outputs from one stage and inputs to the next are matched up by order of declaration. The types of matching output/input parameters must either be identical or compatible (according to API-specific rules). Some APIs also require that the binding semantics of matching output/input parameters are identical. + +* By-name matching: user-defined outputs from one stage and inputs to the next are matched up by their binding semantics. The types of matching output/input parameters must either be identical or compatible (according to API-specific rules). The order of declaration of the parameters need not match. + +Because the matching policy may differ across APIs, the only completely safe option is for parameters passed between pipeline stages to match in terms of order, type, *and* binding semantic. + +> #### Note #### +> Instead of using ordinary function parameters for user-defined varying inputs/outputs, GLSL uses global-scope variable declarations marked with the `in` or `out` modifier. + +### Entry-Point Uniform Parameters + +In the `vertexMain` entry point, the `mvp` parameter is an _entry-point uniform parameter_. + +Entry-point uniform parameters are semantically similar to global-scope shader parameters, but do not pollute the global scope. + +> #### Note #### +> GLSL does not support entry-point `uniform` parameters; all shader parameters must be declared at the global scope. +> Historically, HLSL has supported entry-point `uniform` parameters, but this feature was dropped by recent compilers. diff --git a/docs/user-guide/03-convenience-features.md b/docs/user-guide/03-convenience-features.md new file mode 100644 index 000000000..834485f3c --- /dev/null +++ b/docs/user-guide/03-convenience-features.md @@ -0,0 +1,274 @@ +# Basic Convenience Features + +This topic covers a series of nice-to-have language features in Slang. These features are not supported by HLSL but are introduced to Slang to simplify code development. Many of these features are added to Slang per request of our users. + +## Member functions + +Slang supports defining member functions in `struct`s. For example, it is allowed to write: + +```hlsl +struct Foo +{ + int compute(int a, int b) + { + return a + b; + } +} +``` + +You can use the `.` syntax to invoke member functions: + +```hlsl +Foo foo; +int rs = foo.compute(1,2); +``` + +Slang also supports static member functions, For example: +``` +struct Foo +{ + static int staticMethod(int a, int b) + { + return a + b; + } +} +``` + +Static member functions are accessed the same way as other static members, via either the type name or an instance of the type: + +```hlsl +int rs = Foo.staticMethod(a, b); +``` + +or + +```hlsl +Foo foo; +... +int rs = foo.staticMethod(a,b); +``` + +### Mutability of member function + +For GPU performance considerations, the `this` argument in a member function is immutable by default. If you modify the content in `this` argument, the modification will be discarded after the call and does not affect the input object. If you intend to define a member function that mutates the object, use `[mutating]` attribute on the member function as shown in the following example. + +```hlsl +struct Foo +{ + int count; + + [mutating] + void setCount(int x) { count = x; } + + void setCount2(int x) { count = x; } +} + +void test() +{ + Foo f; + f.setCount(1); // f.count is 1 after the call. + f.setCount2(2); // f.count is still 1 after the call. +} +``` + +## Properties + +Properties provide a convienient way to access values exposed by a type, where the logic behind accessing the value is defined in `getter` and `setter` function pairs. Slang's `property` feature is similar to C# and Swift. +```C# +struct MyType +{ + uint flag; + + property uint highBits + { + get { return flag >> 16; } + set { flag = (flag & 0xFF) + (newValue << 16); } + } +}; +``` + +Or equivalently in a "modern" syntax: + +```C# +struct MyType +{ + uint flag; + + property highBits : uint + { + get { return flag >> 16; } + set { flag = (flag & 0xFF) + (newValue << 16); } + } +}; +``` + +You may also use an explicit parameter for the setter method: +```C# +property uint highBits +{ + set(uint x) { flag = (flag & 0xFF) + (x << 16); } +} +``` + +> #### Note #### +> Slang currently does not support automatically synthesized `getter` and `setter` methods. For example, +> the following code is not supported: +> ``` +> property uint highBits {get;set;} // Not supported yet. +> ``` + +## Initializers +> #### Note #### +> The syntax for defining initializers are subject to future change. + + +Slang supports defining initializers in `struct` types. You can write: +```C# +struct MyType +{ + int myVal; + __init(int a, int b) + { + myVal = a + b; + } +} +``` + +You can use an initializer to construct a new instance by using the type name in a function call expression: +```C# +MyType instance = MyType(1,2); // instance.myVal is 3. +``` + +You may also use C++ style initializer list to invoke an initializer: +```C# +MyType instance = {1, 2}; +``` + +If an initializer does not define any parameters, it will be recognized as *default* initializer that will be automatically called at the definition of a variable: + +```C# +struct MyType +{ + int myVal; + __init(i) + { + myVal = 10; + } +}; + +int test() +{ + MyType test; + return test.myVal; // returns 10. +} +``` + +## Operator Overloading + +Slang allows defining operator overloads as global methods: +```C# +struct MyType +{ + int val; + __init(int x) { val = x; } +} + +MyType operator+(MyType a, MyType b) +{ + return MyType(a.val + b.val); +} + +int test() +{ + MyType rs = MyType(1) + MyType(2); + return rs.val; // returns 3. +} +``` + +Slang currently supports overloading the following operators: `+`, `-`, `*`, `/`, `%`, `&`, `&&`, `|`, `||`, `<`, `>`, `<=`, `>=`, `==`, `!=`, unary `-`, `~` and `!`. + +## `struct` inheritance (limited) + +Slang supports a limited form of inheritance. A derived `struct` type has all the members defined in the base type it is inherited from: + +```C# +struct Base +{ + int a; + void method() {} +} + +struct Derived : Base { int b; } + +void test() +{ + Derived c; + c.a = 1; // OK, a is inherited from `Base`. + c.b = 2; + c.method(); // OK, `method` is inherited from `Base`. +} +``` + +A derived type can be implicitly casted to its base type: +```C# +void acceptBase(Base b) { ... } +void test() +{ + Derived c; + acceptBase(c); // OK, c is implicitly casted to `Base`. +} +``` + +Slang supports controlling whether a type can be inherited from with `[sealed]` and `[open]` attributes on types. +If a base type is marked as `[sealed]`, then inheritance from the type is not allowed anywhere outside the same module (file) that is defining the base type. If a base type is marked as `[open]`, then inheritance is allowed regardless of the location of the derived type. By default, a type is `[sealed]` if no attributes are declared, which means the type can only be inherited by other types in the same module. + +### Limitations + +Please note that the support for inheritance is currently very limited. Common features that comes with inheritance, such as `virtual` functions and multiple inheritance are not supported by the Slang compiler. Implicit down-casting to the base type and use the result as a `mutable` argument in a function call is also not supported. + +Modules +------- + +While you can still organize code using preprocssor `#include`s, Slang also supports a _module_ system. + +### Importing a Module + +At the global scope of a Slang file, you can use the `import` keyword to import another module by name: + +```hlsl +// MyShader.slang + +import YourLibrary; +``` + +This `import` declaration will cause the compiler to look for a module named `YourLibrary` and make its declarations visible in the current scope. +Currently, the compiler will load the module by looking for source file with a matching name (`YourLibrary.slang`) in any of its configured search paths. + +Multiple `import`s of the same module from different input files will only cause the module to be loaded once (there is no need for "include guards" or `#pragma once`). +Note that preprocessor definitions in the current file will not affect the compilation of `import`ed code. + +> #### Note #### +> Future versions of the Slang system will support loading of modules from pre-compiled binaries instead of source code. +> The same `import` keyword will continue to work in that case. + +### Defining a Module + +If you decide to organize your code into modules, then the simplest way is to have each module consist of a single `.slang` file. +Any declarations in your module -- types, functions, etc. -- will be visible to clients that `import` it. + +> #### Note #### +> Any preprocessor definitions inside your module will not be visible to clients; +> as a result you may find it best to switch to `static const` for defining constants. + +> #### Note #### +> A future version of the Slang compiler may support using access-control keywords (such a `public`) to control which declarations in a module are visible to clients. + +Your module may depend on other modules using `import`. +By default, the symbols that are imported into your module are *not* made visible to clients who `import` your module. +You can override this default by using an _exported_ `import`: + +```hlsl +__export import SomeOtherModule; +``` + +This line imports `SomeOtherModule` into the current module, and also re-exports all of the imported symbols from the current module, so that they appear as part of its public interface. diff --git a/docs/user-guide/03-conventional-features.md b/docs/user-guide/03-conventional-features.md deleted file mode 100644 index 8f05c2466..000000000 --- a/docs/user-guide/03-conventional-features.md +++ /dev/null @@ -1,579 +0,0 @@ -Conventional Language Features -============================== - -Many of the language concepts in Slang are similar to those in other real-time shading languages like HLSL and GLSL, and also to general-purpose programming languages in the "C family." -This chapter covers those parts of the Slang language that are _conventional_ and thus unlikley to surprise users who are already familiar with other shading languages, or languages in the C family. - -Readers who are comfortable with HLSL variables, types, functions, statements, as well as concentions for shader parameters and entry points may prefer to skip this chapter. -Readers who are not familiar with HLSL, but who are comfortable with GLSL and/or C/C++, may want to carefully read the sections on types, expressions, shader parameters, and entry points while skimming the others. - -Types ------ - -Slang supports conventional shading language types including scalars, vectors, matrices, arrays, structures, enumerations, and resources. - -> #### Note #### -> Slang does not currently support pointer types as in C/C++. -> Pointers cannot be implemented robustly and completely on many of the target platforms Slang currently supports. - -### Scalar Types - -#### Integer Types - -The following integer types are provided: - -| Name | Description | -|---------------|-------------| -| `int8_t` | 8-bit signed integer | -| `int16_t` | 16-bit signed integer | -| `int` | 32-bit signed integer | -| `int64_t` | 64-bit signed integer | -| `uint8_t` | 8-bit unsigned integer | -| `uint16_t` | 16-bit unsigned integer | -| `uint` | 32-bit unsigned integer | -| `uint64_t` | 64-bit unsigned integer | - -All targets support the 32-bit `int` and `uint` types, but support for the other types depends on the capabilities of each target platform. - -Integer literals can be both decimal and hexidecimal, and default to the `int` type. -A literal can be explicitly made unsigned with a `u` suffix. - -The following floating-point type are provided: - -| Name | Description | -|---------------|------------------------------| -| `half` | 16-bit floating-point number | -| `float` | 32-bit floating-point number | -| `double` | 64-bit floating-point number | - -All targets support the 32-bit `float`, but support for the other types depends on the capabilities of each target platform. - -### Boolean Type - -The type `bool` is used to represent Boolean truth value: `true` and `false`. - -#### The Void Type - -The type `void` is used as a placeholder to represent the result type of functions that don't return anything. - -### Vector Types - -Vector types can be written as `vector` where `T` is a scalar type and `N` is an integer from 2 to 4 (inclusive). -The type `vector` is a vector of `N` _elements_ (also called _components_) each of type `T`. - -As a convenience, pre-defined vector types exist for each scalar type and valid element count, with a name using the formula `<><>`. -For example, `float3` is a convient name for `vector`. - -### Matrix Types - -Matrix types can be written as `matrix` where `T` is a scalar type and both `R` and `C` are integers from 2 to 4 (inclusive). -The type `matrix` is a matrix with _elements_ of type `T`, and comprising `R` rows and `C` columns. - -As a convenience, pre-defined matrix types exist for each scalar type and valid row/column count, with a name using the formula `<><>x<>`. -For example, a `float3x4` is a convient name for `matrix`. - -> #### Note #### -> Readers familiar with GLSL should be aware that a Slang `float3x4` represents a matrix with three rows and four columns, while a GLSL `mat3x4` represents a matrix with three *columns* and four *rows*. -> In most cases, this difference is immaterial because the subscript expression `m[i]` returns a `float4` (`vec4`) in either language. -> For now it is enough to be aware that there is a difference in convention between Slang/HLSL/D3D and GLSL/OpenGL. - -### Array Types - -An array type `T[N]` represents an array of `N` elements of type `T`. -When declaring a variable with an array type, the `[]` brackets come after the variable name, following the C convention for variable declarations: - -```hlsl -// the type of `a` is `int[3]` -int a[3]; -``` - -Sometimes a value with an array type can be declared without an explicit element count. -In some cases the element count is then inferred from the initial value of a variable: - -```hlsl -// the type of `a` is `int[3]` -int a[] = { 1, 2, 3 }; -``` - -In other cases, the result is a _runtime-sized_ array, where the actual element count will be determined later: - -```hlsl -// the type of `b` is `int[]` -void f( int b[] ) -{ ... } -``` - -There are more limits on how runtime-sized arrays can be used than on arrays of statically-known element count. - -> #### Note #### -> In Slang arrays are _value types_, meaning that assignment, parameter passing, etc. semantically copy values of array type. -> In some languages -- notably C, C++, C#, and Java -- assignment and parameter passing for treat arrays as _reference types_, -> meaning that these operations assign/pass a reference to the same underlying storage. - -### Structure Types - -Structure types can be introduced with the `struct` keyword, as in most C-family languages: - -```hlsl -struct MyData -{ - int a; - float b; -} -``` - -> #### Note #### -> Unlike C, and like most other C-family languages, the `struct` keyword in Slang introduces a type directly, and there is no need to combine it with a `typedef`. - -> #### Note #### -> Slang allows for a trailing semicolon (`;`) on `struct` declarations, but does not require it. - -### Enumeration Types - -Enumeration types can be introduced with the `enum` keyword to provide type-safe constants for a range of values: - -```hlsl -enum Channel -{ - Red, - Green, - Blue -} -``` - -> #### Note #### -> Unlike C/C++, `enum` types in Slang are always scoped (like `enum class` in C++). You can write `enum class` in Slang if it makes you happy, but it isn't required. - -### Opaque Types - -The Slang standard library defines a large number of _opaque_ types which provide access to objects that are allocated via GPU APIs. - -What all opaque types have in common is that they are not "first-class" types on most platforms. -Opaque types (and structure or array types that contain them) may be limited in the following ways (depending on the platform): - -* Functions that return opaque types may not be allowed -* Global and `static` variables that use opaque types may not be allowed -* Opaque types may not appear in the element types of buffers, except where explicitly noted as allowed - -#### Texture Types - -Texture types -- including `Texure2D`, `TextureCubeArray`, `RWTexture2D`, and more -- are used to access formatted data for read, write, and sampling operations. -Textures can be used to represent simple images, but also support _mipmapping_ as a way to reduce noise when sampling at lower than full resolution. -The full space of texture types follows the formula: - - <>Texture<><><><> - -where: - -* The _access_ can be read-only (no prefix), read-write (`RW`), or read-write with a guarantee of rasterization order for operations on the given resource (`RasterizerOrdered`). -* The _base shape_ can be `1D`, `2D`, `3D`, or `Cube`. -* The _multisample-ness_ can non-multiple-sample, or multi-sampled (`MS`). -* The _array-ness_ can either be non-arrayed, or arrayed (`Array`). -* The _element type_ can either be explicitly specified (``) or left as the default of `float4` - -Not all combinations of these options are supported, and some combinations may be unsupported on some targets. - -#### Sampler - -Sampler types encapsulate parameters that control addressing and filtering for texture-sampling operations. -There are two sampler types: `SamplerState` and `SamplerComparisonState`. -`SamplerState` is applicable to most texture sampling operations, while `SamplerComparisonState` is used for "shadow" texture sampling operations which compare texels to a reference value before filtering. - -> #### Note #### -> Some target platforms and graphics APIs do not support separation of textures and sampling state into distinct types in shader code. -> On these platforms the Slang texture types include their own sampling state, and the sampler types are placeholder types that carry no data. - -#### Buffers - -There are multiple buffer types supported by modern graphics APIs, with substantially different semantics. - -##### Formatted Buffers - -Formatted buffers (sometimes referred to as "typed buffers" or "buffer textures") are similar to 1D textures (in that they support format conversion on loads), without support for mipmapping. -The formula for formatted buffer types is: - - <>Buffer<><> - -Where the _access_, _array-ness_, and _element type_ are the same as for textures, with the difference that _element type_ is not optional. - -A buffer type like `Buffer` represents a GPU resource that stores one or more values that may be fetched as a `float4` (but might internally be stored in another format, like RGBA8). - -##### Flat Buffers - -Flat buffers differ from formatted buffers in that they do not support format conversion. -Flat buffers are either _structured_ buffers or _byte-addressed_ buffers. - -Structured buffer types like `StructuredBuffer` include an explicit element type `T` that will be loaded and stored from the buffer. -Byte-addressed buffer types like `ByteAddressBuffer` do not specify any particular element type, and instead allow for values to be loaded or stored from any (suitably aligned) byte offset in the buffer. -Both structured and byte-addressed bufers can use an _access_ to distinguish between read-only and read-write usage. - -##### Constant Buffers - -Constant buffers (sometimes also called "uniform buffers") are typically used to pass immutable parameter data from a host application to GPU code. -The constant buffer type `ConstantBuffer` includes an explicit element type. -Unlike formatted or flat buffers, a constant buffer conceptualy contains only a *single* value of its element type, rather than one or more values. - -Expressions ------------ - -Slang supports the following expression forms with nearly identical syntax to HLSL, GLSL, and C/C++: - -* Literals: `123`, `4.56`, `false` - -> #### Note #### -> Unlike C/C++, but like HLSL/GLSL, an unsuffixed floating-point literal has the `float` type in Slang, rather than `double` - -* Member lookup: `structValue.someField`, `MyEnumType.FirstCase` - -* Function calls: `sin(a)` - -* Vector/matrix initialization: `int4(1, 2, 3, 4)` - -* Casts: `(int) x`, `double(0.0)` - -* Subscript (indexing): `a[i]` - -* Initializer lists: `int b[] = { 1, 2, 3 };` - -* Assignment: `l = r` - -* Operators: `-a`, `b + c`, `d++`, `e %= f` - -> #### Note #### -> Like HLSL but unlike most other C-family languages, the operators `&&` and `||`, along with the conditional operator `?:` do *not* currently perform "short-circuiting"; -> they evaluate all of their operands unconditionally. -> The default behavior of these operators is likely to change in a future Slang release. - -Additional expression forms specific to shading languages follow. - -### Operators on Vectors and Matrices - -The ordinary unary and binary operators can also be applied to vectors and matrices, where they apply element-wise. - -> #### Note #### -> In GLSL, most operators apply component-wise to vectors and matrices, but the multiplication operator `*` computes the traditional linear-algebraic product of two matrices, or a matrix and a vector. -> Where a GLSL programmer would write `m * v` to multiply a `vec3x4` by a `vec3`, a Slang programmer should write `mul(v,m)` to multiply a `float3` by a `float3x4`. -> In this example, the order of operands is reversed to account for the difference in row/column conventions. - -### Swizzles - -Given a value of vector type, a _swizzle_ expression extracts one or more of the elements of the vector to produce a new vector. -For example, if `v` is a vector of type `float4`, then `v.xy` is a `float2` consisting of the `x` and `y` elements of `v`. -Swizzles can reorder elements (`v.yx`) or include duplicate elements (`v.yyy`). - -> #### Note #### -> Unlike GLSL, Slang only supports `xyzw` and `rgba` as swizzle elements, and not the seldom-used `stpq`. - -> #### Note #### -> Unlike HLSL, Slang does not currently support matrix swizzle syntax. - -Statements ----------- - -Slang supports the following statement forms with nearly identical syntax to HLSL, GLSL, and C/C++: - -* Expression statements: `f(a, 3);`, `a = b * c;` - -* Local variable declarations: `int x = 99;` - -* Blocks: `{ ... }` - -* Empty statement: `;` - -* `if` statements - -* `switch` statements - -> #### Note #### -> Unlike C/C++, `case` and `default` statements must be directly nested under a `switch`, rather than being allowed under nested control flow (Duff's Device and similar idioms are not allowed). -> In addition, while multiple `case`s can be grouped together, all other forms of "fallthrough" are unsupported. - -* `for` statements - -* `while` statements - -* `do`-`while` statements - -* `break` statements - -* `continue` statements - -* `return` statements - -> #### Note #### -> Slang does not support the C/C++ `goto` keyword. - -> #### Note #### -> Slang does not support the C++ `throw` keyword. - -Additional statement forms specific to shading languages follow. - -### Discard Statements - -A `discard` statement can be used in the context of a fragment shader to terminate shader execution for the current fragment, and to cause the graphics system to discard the corresponding fragment. - -Functions ---------- - -Slang supports function definitions with traditional C syntax: - -```hlsl -float addSomeThings(int x, float y) -{ - return x + y; -} -``` - -Slang supports overloading of functions based on parameter types. - -Function parameters may be marked with a _direction_ qualifier: - -* `in` (the default) indicates a by-value input parameter -* `out` indicates an output parameter -* `inout` or `in out` indicates an input/output parameter - -> #### Note #### -> The `out` and `inout` directions are superficially similar to non-`const` reference parameters in C++. -> In cases that do not involve aliasing of mutable memory, the semantics should be equivalent. - -Preprocessor ------------- - -Slang supports a C-style preprocessor with the following directives; - -* `#include` -* `#define` -* `#undef` -* `#if`, `#ifdef`, `#ifndef` -* `#else`, `#elif` -* `#endif` -* `#error` -* `#warning` -* `#line` -* `#pragma`, including `#pragma once` - -> #### Note #### -> Variadic macros are not currently supported by the Slang preprocessor. - -Attributes ----------- - -_Attributes_ are a general syntax for decorating declarations and statements with additional semantic information or meta-data. -Attributes are surrounded with square brackets (`[]`) and prefix the declaration or statement they apply to. - -For example, an attribute can indicate the programmer's desire that a loop be unrolled as much as possible: - -```hlsl -[unroll] -for(int i = 0; i < n; i++) -{ /* ... */ } -``` - -> #### Note #### -> Traditionally, all attributes in HLSL used a single layer of `[]` brackets, matching C#. -> Later, C++ borrowed the idea from C# but used two layers of brackets (`[[]]`). -> Some recent extensions to HLSL have used the C++-style double brackets instead of the existing single brackets syntax. -> Slang tries to support both alternatives uniformly. - -Global Variables and Shader Parameters --------------------------------------- - -By default, global-scope variable declarations in Slang represent _shader parameters_ passed from host application code into GPU code. -Programmers must explicitly mark a global-scope variable with `static` for it to be treated as a shader parameter, even if the variable is marked `const`: - -```hlsl -// a shader parameter: -float a; - -// also a shader parameter (despite `const`): -const int b = 2; - -// a "thread-local" global variable -static int c = 3; - -// a compile-time constant -static const int d = 4; -``` - -### Global Constants - -A global-scope `static const` variable defines a compile-time constant for use in shader code. - -### Global-Scope Static Variables - -A non-`const` global-scope `static` variable is conceptually similar to a global variable in C/C++, with the key difference that it has distinct storage per *thread* rather than being truly global. -Each logical thread of shader execution initiated by the GPU will be allocated fresh storage for these `static` variables, and values written to those variables will be lost when a shader thread terminates. - -> #### Note #### -> Some target platforms do not support `static` global variables in all use cases. -> Support for `static` global variables should be seen as a legacy feature, and further use is discouraged. - -### Global Shader Parameters - -Global shader parameters may use any type, including both opaque and non-opaque types: - -```hlsl -ConstantBufer c; -Texture2D t; -float4 color; -``` - -To avoid confusion, the Slang compiler will warn on any global shader parameter that includes non-opaque types, because it is likely that a user thought they were declaring a global constant or a traditional global variable. -This warning may be suppressed by marking the parameter as `uniform`: - -```hlsl -// WARNING: this declares a global shader parameter, not a global variable -int gCounter = 0; - -// OK: -uniform float scaleFactor; -``` - -#### Legacy Constant Buffer Syntax - -For compatibility with existing HLSL code, Slang also supports global-scope `cbuffer` declarations to introduce constant buffers: - -```hlsl -cbuffer PerFrameCB -{ - float4x4 mvp; - float4 skyColor; - // ... -} -``` - -A `cbuffer` declaration like this is semantically equivalent to a shader parameter declared using the `ConstantBuffer` type: - -```hlsl -struct PerFrameData -{ - float4x4 mvp; - float4 skyColor; - // ... -} -ConstantBuffer PerFrameCB; -``` - -#### Explicit Binding Markup - -For compatibility with existing codebases, Slang supports pre-existing markup syntax for associating shader parameters of opaque types with binding information for specific APIs. - -Binding information for Direct3D platforms may be specified using `register` syntax: - -```hlsl -Texture2D a : register(t0); -Texture2D b : register(t1, space0); -``` - -Binding information for Vulkan (and OpenGL) may be specified using `[[vk::binding(...)]]` attributes - -```hlsl -[[vk::binding(0)]] -Texture2D a; - -[[vk::binding(1, 0)]] -Texture2D b; -``` - -A single parameter may use both the D3D-style and Vulkan-style markup, but in each case explicit binding markup only applies to the API family for which it was designed. - -> #### Note #### -> Explicit binding markup is tedious to write and error-prone to maintain. -> It is almost never required in Slang codebases. -> The Slang compiler can automatically synthesize bindings in a completely deterministic fashion and in most cases the bindings it generates are the as what a programmer would have written manually. - -Shader Entry Points -------------------- - -An _entry point_ is a function that can be used as the starting point for execution of a GPU thread. - -Here is an example of an entry-point function in Slang: - -```hlsl -[shader("vertex")] -float4 vertexMain( - float3 modelPosition : POSITION, - uint vertexID : SV_VertexID, - uniform float4x4 mvp) - : SV_Position -{ /* ... */ } -``` - -In the following sections we will use this example to explain important facets of entry point declarations in Slang. - -### Entry Point Attribute and Stages - -The `[shader(...)]` attribute is used to mark a function in Slang as a shader entry point, and also to specify which pipeline stage it is meant for. -In this example, the `vertexMain` shader indicates that it is meant for the `vertex` stage of the traditional rasterization pipeline. -Rasterization, compute, and ray-tracing pipelines each define their own stages, and new versions of graphics APIs may introduce new stages. - -For compatibility with legacy codebases, Slang supports code that leaves off `[shader(...)]` attributes; in these cases application developers must specify the names and stages for their entry points via explicit command-line or API options. -It is recommended that new codebases always use `[shader(...)]` attributes both to simplify their workflow, and to make code more explicit and "self-documenting." - -> #### Note #### -> In GLSL, a file of shader code may only include one entry point, and all code `#include`d into that file must be compatible with the stage of that entry point. By default, GLSL requires that an entry point be called `main`. -> Slang allows for multiple entry points to appear in a file, for any combination of stage, and with any valid identifier as a name. - -### Parameters - -The parameter of an entry-point function represent either _varying_ or _uniform_ inputs. -Varying inputs are those that may vary over threads invoked as part of the same batch (a draw call, compute dispatch, etc.), while uniform inputs are those that are guaranteed to be the same for all threads in a batch. -Entry-point parameters in Slang default to varying, but may be explicitly marked `uniform`. - -If an entry-point function declares a non-`void` result type, then its result behaves like an anonymous `out` parameter that is varying. - -### Binding Semantics - -The varying parameters of an entry point must declare a _binding semantic_ to indicate how those parameters should be connected to the execution environment. -A binding semantic for a parameter may be introduced by suffixing the variable name with a colon (`:`) and an identifier for the chosen binding semantic. -A binding semantic for a function result is introduced similarly, but comes after the parameter list. - -It is not shown in this example, but binding semantics may also be applied to individual `struct` fields, in cases where a varying parameter of `struct` type is used. - -#### System-Defined Binding Semantics - -In the `vertexMain` entry point, the `vertexID` parameter uses the `SV_VertexID` binding semantic, which is a _system-defined_ binding semantic. -Standard system-defined semantics are distinguished by the `SV_` prefix. - -A system-defined binding semantic on an input parameter indicates that the parameter should receive specific data from the GPU as defined by the pipeline and stage being used. -For example, in a vertex shader the `SV_VertexID` binding semantic on an input yields the ID of the particular vertex being processed on the current thread. - -A system-defined binding semantic on an ouptput parameter or function result indicates that when a shader thread returns from the entry point the value stored in that output should be used by the GPU in a specific way defined by the pipeline and stage being used. -For example, in a vertex shader the `SV_Position` binding semantic on an output indicates that it represents a clip-space position that should be communicated to the rasterizer. - -The set of allowed system-defined binding semantics for inputs and outputs depends on the pipeline and stage of an entry point. -Some system-defined binding semantics may only be available on specific targets or specific versions of those targets. - -> #### Note #### -> Instead of using ordinary function parameters with system-defined binding semantics, GLSL uses special system-defined global variables with the `gl_` name prefix. -> Some recent HLSL features has introduced special globally-defined functions that behave similarly to these `gl_` globals. - -#### User-Defined Binding Semantics - -In the `vertexMain` entry point, the `modelPosition` parameter used the `POSITION` binding semantic, which is a _user-defined_ binding semantic. - -A user-defined binding semantic on an input indicates that the parameter should receive data with a matching binding semantic from a preceding stage. -A user-defined binding semantic on an output indicates that the parameter should provide data to a parameter with a matching binding semantic in a following stage. - -Whether or not inputs and outputs with user-defined binding semantics are allowed depends on the pipeline and stage of an entry point. - -Different APIs and different stages within the same API may match up entry point inputs/outputs with user-defined binding semantics in one of two ways: - -* By-index matching: user-defined outputs from one stage and inputs to the next are matched up by order of declaration. The types of matching output/input parameters must either be identical or compatible (according to API-specific rules). Some APIs also require that the binding semantics of matching output/input parameters are identical. - -* By-name matching: user-defined outputs from one stage and inputs to the next are matched up by their binding semantics. The types of matching output/input parameters must either be identical or compatible (according to API-specific rules). The order of declaration of the parameters need not match. - -Because the matching policy may differ across APIs, the only completely safe option is for parameters passed between pipeline stages to match in terms of order, type, *and* binding semantic. - -> #### Note #### -> Instead of using ordinary function parameters for user-defined varying inputs/outputs, GLSL uses global-scope variable declarations marked with the `in` or `out` modifier. - -### Entry-Point Uniform Parameters - -In the `vertexMain` entry point, the `mvp` parameter is an _entry-point uniform parameter_. - -Entry-point uniform parameters are semantically similar to global-scope shader parameters, but do not pollute the global scope. - -> #### Note #### -> GLSL does not support entry-point `uniform` parameters; all shader parameters must be declared at the global scope. -> Historically, HLSL has supported entry-point `uniform` parameters, but this feature was dropped by recent compilers. diff --git a/docs/user-guide/05-compiling.md b/docs/user-guide/05-compiling.md new file mode 100644 index 000000000..67d9d31ef --- /dev/null +++ b/docs/user-guide/05-compiling.md @@ -0,0 +1,493 @@ +Compiling Code with Slang +========================= + +This chapter presents the ways that the Slang system supports compiling and composing shader code. +We will start with a discussion of the mental model that Slang uses for compilation. +Next we will cover the command-line Slang compiler, `slangc`, and how to use it to perform offline compialtion. +Finally we will discuss the Slang compilation API, which can be used to integrate Slang compilation into an application at runtime, or to build custom tools that implement application-specific compilation policy. + +Concepts +-------- + +For simple scenarios it may be enough to think of a shader compiler as a box where source code goes in and compiled kernels come out. +Most real-time graphics applications end up needing more control over shader compilation, and/or more information about the results of compilation. +In order to make use of the services provided by the Slang compilation system, it is useful to start with a clear model of the concepts that are involved in compilation. + +### Source Units + +At the finest granularity, code is fed to the compiler in _source units_ which are most often stored as files on disk or strings of text in memory. +The compilation model largely does not care whether source units have been authored by human programmers or automatically assembled by other tools. + +If multiple source units are specified as part of the same compile, they will be preprocessed and parsed independently. +However, a source unit might contain `#include` directives, so that the preprocessed text of that source unit includes the content of other files. +Note that the `#include`d files do not become additional source units; they are just part of the text of a source unit that was fed to the compiler. + +### Translation Units and Modules + +Source units (such as files) are grouped into _translation units_, and each translation unit will produce a single _module_ when compiled. + +While the source units are all preprocessed and parsed independently, semantic checking is applied to a translation unit as a whole. +One source file in a translation unit may freely refer to declarations in another translation unit without any need for forward declarations. For example: + +```hlsl +// A.slang + +float getFactor() { return 10.0; } +``` + +```hlsl +// B.slang + +float scaleValue(float value) +{ + return value * getFactor(); +} +``` + +In this example, the `scaleValue()` function in `B.slang` can freely refer to the `getFactor()` function in `A.slang` because they are part of the same translation unit. + +It is allowed, and indeed common, for a translation unit to contain only a single source unit. +For example, when adapting an existing codebase with many `.hlsl` files, it is appropraite to compile each `.hlsl` file as its own translation unit. +A modernized codebase might decide to compile multiple `.slang` files in a single directory as a single translation unit. + +The result of compiling a translation unit is a module in Slang's internal intermediate representation (IR). + +### Entry Points + +A translation unit / module may contain zero or more entry points. +Slang supports two models for identifying entry points when compiling. + +#### Entry Point Attributes + +By default, the compiler wll scan a translation unit for function declarations marked with the `[shader(...)]` attribute; each such function will be identified as an entry point in the module. +Developers are encouraged to use this model because it makes directly documents intention and makes source code less dependent on external compiler configuration options. + +#### Explicit Entry Point Options + +For compatibility with existing code, the Slang compiler also supports explicit specification of entry point functions using configuration optiosn external to shader source code. +When these options are used the compiler will *ignore* all `[shader(...)]` attributes and only use the explicitly-specified entry points intead. + +### Shader Parameters + +A translation unit / module may contain zero or more global shader parameters. +Similarly, each entry point may define zero or more entry-point `uniform` shader parameters. + +The shader parameters of a module or entry point are significant because they describe the interface between host application code and GPU code. +It is important that both the application and generated GPU kernel code agree on how parameters are laid out in memory and/or how they are assigned to particular API-defined registers, locations, or other "slots." + +### Targets + +Within the Slang system a _target_ represents a particular platform and set of capabilities that output code can be generated for. +A target includes information such as: + +* The _format_ that code should be generated in: SPIR-V, DXIL, etc. + +* A _profile_ that specifies a general feature/capability level for the target: D3D Shader Model 5.1, GLSL version 4.60, etc. + +* Optional _capabilities_ that should be assumed available on the target: for example, specific Vulkan GLSL extensions + +* Options that impact code generation: floating-point strictness, level of debug information to generate, etc. + +Slang supports compiling for multiple targets in the same compilation session. +When using multiple targets at a time, it is important to understand the distinction between the _front-end_ of the compiler, and the _back-end_: + +* The compiler front-end comprises preprocessing, parsing, and semantic checking. The front-end runs once for each translation unit and its results are shared across all targets. + +* The compiler back-end generates output code, and thus runs once per target. + +> #### Note #### +> Because front-end actions, including preprocessing, only run once, across all targets, the Slang compiler does not automatically provide any target-specific preprocessor `#define`s that can be used for preprocessor conditionals. +> Applications that need target-specific `#define`s should always compile for one target at a time, and set up their per-target preprocessor state manually. + +### Layout + +While the front-end of the compiler determines what the shader parameters of a module or entry point are, the _layout_ for those parameters is dependent on a particular compilation target. +A `Texture2D` might consume a `t` register for Direct3D, a `binding` for Vulkan, or just plain bytes for CUDA. + +The details of layout in Slang will come in a later chapter. +For the purposes of the compilation model it is important to note that the layout computed for shader parameters depends on: + +* What modules and entry points are being used together; these define which parameters are relevant. + +* Some well-defined ordering of those parameters; this defines which parameters should be laid out before which others. + +* The rules and constraints that the target imposes on layout. + +An important design choice in Slng is give the user of the compiler control over these choices. + +### Composition + +The user of the Slang compiler communicates the modules and entry points that will be used together, as well as their relative order, using a system for _composition_. + +A _component type_ is a unit of shader code composition; both modules and entry points are examples of component types. +A _composite_ component type is formed from a list of other component types (for example, one module and two entry points) and can be used to define a unit of shader code that is meant to be used together. + +Once a programmer has formed a composite of all the code they intend to use together, they can query the layout of the shader parameters in that composite, or request kernel code generation for its entry points. + +### Kernels + +A _kernel_ is generated code for an entry point. +The same entry point can be used to generate many different kernels. +First, and entry point can be compiled for different targets, resulting in different kernels in the appropriate format for each target. +Second, different compositions of shade rcode can result in different layouts, which leads to different kernels being required. + +Command-Line Compilation with `slangc` +-------------------------------------- + +The `slangc` tool, included in binary distributions of Slang, is a command-line compiler that can handle most simple compilation tasks. +`slangc` is intended to be usable as a replacement for tools like `fxc` and `dxc`, and covers most of the same use cases. + +### Example + +Here we will repeat the example used in the [Getting Started](01-get-started.md) chapter. +Given the following Slang code: + +```hlsl +// hello-world.slang +StructuredBuffer buffer0; +StructuredBuffer buffer1; +RWStructuredBuffer result; + +[shader("compute")] +[numthreads(1,1,1)] +void computeMain(uint3 threadId : SV_DispatchThreadID) +{ + uint index = threadId.x; + result[index] = buffer0[index] + buffer1[index]; +} +``` + +we can compile the `computeMain()` entry point to SPIR-V using the following command line: + +```bat +slangc hello-world.slang -entry computeMain -target spirv -o hello-world.spv +``` + +### Source Files and Translation Units + +The `hello-world.slang` argument here is specifying an input file. +Each input file specified on the command line will be a distinct source unit during compilation. +Slang supports multiple file-name extensions for input files, but the most common ones will be `.hlsl` for existing HLSL code, and `.slang` for files written specifically for Slang. + +If multiple source files are passed to `slangc`, they will be grouped into translation units using the following rules: + +* If there are any `.slang` files, then all of them will be grouped into a single translation unit + +* Each `.hlsl` file will be grouped into a distinct translation unit of its own + +### Entry Points + +When using `slangc`, you will typically want to identify which entry point(s) you intend to compile. +The `-entry computeMain` option selects an entry point to be compiled to output code in this invocation of `slangc`. + +Because the `computeMain()` entry point in this example has a `[shader(...)]` attribute, the compiler is able to deduce that it should be compiled for the `compute` stage. +In code that does not use `[shader(...)]` attributes, a `-entry` option should be followed by a `-stage` option to specify the stage of the entry point: + +```bat +slangc hello-world.slang -entry computeMain -stage compute -o hello-world.spv +``` + +### Targets + +Our example uses the option `-target spirv` to introduce a compilation target; in this case, code will be generated as SPIR-V. +The argument of a `-target` option specified the format to use for the target; common values are `dxbc`, `dxil`, and `spirv`. + +Additional options for a target can be specified after the `-target` option. +For example, a `-profile` option can be used to specify a profile that should be used. +Slang provides two main kinds of profiles for use with `slangc`: + +* Direct3D "Shader Model" profiles have names like `sm_5_1` and `sm_6_3` + +* GLSL versions can be used as profile with names like `glsl_430` and `glsl_460` + +### Kernels + +A `-o` option indicates that kernel code should be written to a file on disk. +In our example, the SPIR-V kernel code for the `computeMain()` entry point will be written to the file `hello-world.spv`. + +### Working with Multiples + +It is possible to use `slangc` with multiple input files, entry points, or targets. +In these cases, the ordering of arguments on the command line becomes significant. + +When an option modifies or relates to another command-line argument, it implicitly applies to the most recent relevant argument. +For example: + +* If there are multiple input files, then an `-entry` option applies to the preceding input file + +* If there are mutliple entry points, then a `-stage` option applies to the preceding `-entry` option + +* If there are multiple targets, then a `-profile` option applies to the preceding `-target` option + +Kernel `-o` options are the most complicated case, because they depend on both a target and entry point. +A `-o` option applies to the preceding entry point, and the compiler will try to apply it to a matching target based on its file extension. +For example, a `.spv` output file will be matched to a `-target spriv`. + +The compiler makes a best effort to support complicated cases with multiple files, entry points, and targets. +Users with very complicated compilation requirements will probably be better off using multiple `slangc` invocations or migrating to the compilation API. + +### Additional Options + +The main other options are: + +* `-D` or `-D=` can be used to introduce preprocessor macros. + +* `-I` or `-I ` can be used to introduce a _search path_ to be used when resolving `#include` directives and `import` declarations. + +* `-g` can be used to enable inclusion of debug information in output files (where possible and implemented) + +* `-O` can be used to control optimization levels when the Slang compiler invokes downstream code generator + +### Convenience Features + +The `slangc` compiler provides a few conveniences for command-line compilation: + +* Most options can appear out of order when they are unambiguous. For example, if there is only a single translation unit a `-entry` option can appear before or after any file. + +* A `-target` option can be left out if it can be inferred from the only `-o` option present. For example, `-o hello-world.spv` already implies `-target spriv`. + +* If a `-o` option is left out then kernel code will be written to the standard output. This output can be piped to a file, or can be printed to a console. In the latter case, the compiler will automatically disassemble binary formats for printing. + +### Limitations + +The `slangc` tool is meant to serve the needs of many developers, including those who are currently using `fxc`, `dxc`, or similar tools. +However, some applications will benefit from deeper integration of the Slang compiler into application-specific code and workflows. +Notable features that Slang supports which cannot be accessed from `slangc` include: + +* Slang can provide _reflection_ information about shader parameters and their layouts for particular targets; this information is not currently output by `slangc`. + +* Slang allows applications to control the way that shader modules and entry points are composed (which in turn influences their layout); `slangc` currently implements a single default policy for how to generate a composition of shader codce. + +Applications that more control over compilation are encouraged to use the C++ compilation API described in the next section. + +Using the Compilation API +------------------------- + +The C++ API provided by Slang is meant to provide more complete control over compilation for applications that need it. +The additional level of control means that some tasks require more individual steps than they would when using a one-size-fits-all tool like `slangc`. + +### "COM-lite" Components + +Many parts of the Slang C++ API use interfaces that follow the design of COM (the Component Object Model). +Some key Slang interfaces are binary-compatible with existing COM interfaces. +However, the Slang API does not depend on any runtime aspects of the COM system, even on Windows; the Slang system can be seen as a "COM-lite" API. + +The `ISlangUnknown` interface is equivalent to (and binary-compatible with) the standard COM `IUnknown`. +Application code is expected to correctly maintain the reference counts of `ISlangUnknown` objects returned from API calls; the `SlangComPtr` "smart pointer" type is provided as an optional convenience for applications that want to use it. + +Many Slang API calls return `SlangResult` values; this type is equivalent to (and binary-compatible with) the standard COM `HRESULT` type. +As a matter of convention, Slang API calls return a zero value (`SLANG_OK`) on success, and a negative value on errors. + +### Creating a Global Session + +A Slang _global session_ uses the interface `slang::IGlobalSession` and it represents a connection from an application to a particular implementation of the Slang API. +A global session is created using the function `slang::createGlobalSession()`: + +```c++ +SlangComPtr globalSession; +slang::createGlobalSession(globalSession.writeRef()); +``` + +When a global session is created, the Slang system will load its internal representation of the _standard library_ that the compiler provides to user code. +The standard library can take a significant amount of time to load, so applications are advised to use a single global session if possible, rather than creating and then disposing of one for each compile. + +> #### Note #### +> Currently, the global session type is *not* thread-safe. +> Applications that wish to compile on multiple threads will need to ensure that each concurrent thread copmiles with a distinct global session. + +### Creating a Session + +A _session_ uses the interface `slang::ISession`, and represents a scope for compilation with a consistent set of compiler options. +In particular, all compilation with a single session will share: + +* A list of enabled compilation targets (with their options) + +* A list of search paths (for `#include` and `import`) + +* A list of pre-defined macros + +In addition, a session provides a scope for the loading and re-use of modules. +If two pieces of code compiled in a session both `import` the same module, then that module will only be loaded and compiled once. + +To create a session, use the `IGlobalSession::createSession()` method: + +```c++ +SessionDesc sessionDesc; +/* ... fill in `sessionDesc` ... */ +SlangComPtr session; +globalSession->createSession(sessionDesc, session.writeRef()); +``` + +#### Targets + +The `SessionDesc::targets` array can be used to describe the list of targets that the application wants to support in a session. +Often, this will consist of a single target. + +Each target is described with a `TargetDesc` which includes options to control code generation for the target. +The most important fields of the `TargetDesc` are the `format` and `profile`; most others can be left at their default values. + +The `format` field should be set to one of the values from the `SlangCompileTarget` enumeration. +For example: + +```c++ +TargetDesc targetDesc; +targetDesc.format = SLANG_FORMAT_SPIRV; +``` + +The `profile` field must be set with the ID of one of the profiles supported by the Slang compiler. +The exact numeric value of the different profiles is not currently stable across compiler versions, so applications should look up a chosen profile using `IGlobalSession::findProfile`. +For example: + +```c++ +targetDesc.profile = globalSession->findProfile("glsl_450"); +``` + +Once the chosen `TargetDesc`s have been initialized, they can be attached to the `SessionDesc`: + +```c++ +sessionDesc.targets = &targetDesc; +sessionDesc.targetCount = 1; +``` + +#### Search Paths + +The search paths on a session provide the paths where the compiler will look when trying to resolve a `#include` directive or `import` declaration. +The search paths can be set in the `SessionDesc` as an array of `const char*`: + +```c++ +const char* searchPaths[] = { "myapp/shaders/" }; +sessionDesc.searchPaths = searchPaths; +sessionDesc.searchPathCount = 1; +``` + +#### Pre-Defined Macros + +The pre-defined macros in a session will be visible at the start of each source unit that is compiled, including source units loaded via `import`. +Each pre-defined macro is described with a `PreprocessorMacroDesc`, which has `name` and `value` fields: + +```c++ +PreprocessorMacroDesc fancyFlag = { "ENABLE_FANCY_FEATURE", "1" }; +sessionDesc.preprocessorMacros = &fancyFlag; +sessionDesc.preprocessorMacroCount = 1; +``` + +### Loading a Module + +The simplest way to load code into a session is with `ISession::loadModule()`: + +```c++ +SlangComPtr module = session->loadModule("MyShaders"); +``` + +Executing `loadModule("MyShaders")` in host C++ code is similar to using `import MyShaders` in Slang code. +The session will search for a matching module (usually in a file called `MyShaders.slang`) and will load and compile it (if it hasn't been done already). + +Note that `loadModule()` does not provide any ways to customize the compiler configuration for that specific module. +The preprocessor environment, search paths, and targets will always be those specified for the session. + +### Capturing Diagnostic Output + +Compilers produce various kinds of _diagnostic_ output when compiling code. +This includes not only error messages when compilation fails, but also warnings and other helpful messages that may be produced even for successful compiles. + +Many operations in Slang, such as `ISession::loadModule()` can optionally produce a _blob_ of diagnostic output. +For example: + +```c++ +SlangComPtr diagnostics; +SlangComPtr module = session->loadModule("MyShaders", diagnostics.writeRef()); +``` + +In this example, if any diagnostic messages were produced when loading `MyShaders`, then the `diagnostics` pointer will be set to a blob that contains the textual content of those diagnostics. + +The content of a blob can be accessed with `getBufferPointer()`, and the size of the content can be accessed with `getBufferSize()`. +Diagnostic blobs produces by the Slang compiler are always null-terminated, so that they can be used with C-style sting APIs: + +```c++ +if(diagnostics) +{ + fprintf(stderr, "%s\n", (const char*) diagnostics->getBufferPointer()); +} +``` + +> #### Note #### +> The `slang::IBlob` interface is binary-compatible with the `ID3D10Blob` and `ID3DBlob` interfaces used by some Direct3D compilation APIs. + +### Entry Points + +When using `loadModule()` applications should ensure that entry points in their shader code are always marked with appropriate `[shader(...)]` attributes. +For example, if `MyShaders.slang` contained: + +```hlsl +[shader("compute")] +void myComputeMain(...) { ... } +``` + +then the Slang system will automatically detect and validate this entry point as part of a `loadModule("MyShaders")` call. + +After a module has been loaded, the application can look up entry points in that module using `IModule::findEntryPointByName()`: + +```c++ +SlangComPtr computeEntryPoint; +module->findEntryPointByName("myComputeMain", computeEntryPoint.writeRef()); +``` + +### Composition + +An application might load any number of modules with `loadModule()`, and those modules might contain any number of entry points. +Before GPU kernel code can be generated it is first necessary to decide which pieces of GPU code will be used together. + +Both `slang::IModule` and `slang::IEntryPoint` inherit from `slang::IComponentType`, because both can be used as components when composing a shader program. +A composition can be created with `ISession::createCompositeComponentType()`: + +```c++ +IComponentType* components[] = { module, entryPoint }; +SlangComPtr program; +session->createCompositeComponentType(components, 2, program.writeRef()); +``` + +As discussed earlier in this chapter, the composition operation serves two important purposes. +First, it establishes which code is part of a compiled shader program and which is not. +Second, it established an ordering for the code in a program, which can be used for layout. + +### Layout and Reflection + +Some applications need to perform reflection on shader parameters and their layout, whether at runtime or as part of an offline compilation tool. +The Slang API allows layout to be queried on any `IComponentType` using `getLayout()`: + +```c++ +slang::ProgramLayout* layout = program->getLayout(); +``` + +> #### Note #### +> In the current Slang API, the `ProgramLayout` type is not reference-counted. +> Currently, the lifetime of a `ProgramLayout` is tied to the `IComponentType` that returned it. +> An application must ensure that it retains the given `IComponentType` for as long as it uses the `ProgramLayout`. + +Note that because both `IModule` and `IEntryPoint` inherit from `IComponentType`, they can also be queried for their layouts individually. +The layout for a module comprises just its global-scope parameters. +The layout for an entry point comprises just its entry-point parameters (both `uniform` and varying). + +The details of how Slang computes layout, what guarantees it makes, and how to inspect the reflection information will be discussed in a later chapter. + +Because the layout computed for shader parameters may depend on the compilation target, the `getLayout()` method actually takes a `targetIndex` parameter that is the zero-based index of the target for which layout information is being queried. +This parameter defaults to zero as a convenience for the common case where applications use only a single compilation target at runtime. + +### Kernel Code + +Given a composed `IComponentType`, an application can extract kernel code for one of its entry points using `IComponentType::getEntryPointCode()`: + +```c++ +int entryPointIndex = 0; // only one entry point +int targetIndex = 0; // only one target +SlangComPtr kernelBlob; +program->getEntryPointCode( + entryPointIndex, + targetIndex, + kernelBlob.writeRef(), + diagnostics.writeRef()); +``` + +Any diagnostic messages related to back-end code generation (for example, if the chosen entry point requires features not available on the chosen target) will be written to `diagnostics`. +The `kernelBlob` output is a `slang::IBlob` that can be used to access the generated code (whether binary or textual). +In many cases `kernelBlob->getBufferPointer()` can be passed directly to the appropriate graphics API to load kernel code onto a GPU. -- cgit v1.2.3