diff options
| author | Yong He <yonghe@outlook.com> | 2024-02-27 13:32:43 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-02-27 13:32:43 -0800 |
| commit | 1e5d0b31d28bdbf0d220c89debe5f9cc6b82a6fa (patch) | |
| tree | 930282d397bf76b3c7fc6a77a8fa35d8916d48e0 /docs | |
| parent | 92cc3a715d7fdbc460464a202ab404f8bd4e570c (diff) | |
Add documentation for link-time specialization. (#3638)
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/user-guide/08-compiling.md | 89 | ||||
| -rw-r--r-- | docs/user-guide/09-targets.md | 2 | ||||
| -rw-r--r-- | docs/user-guide/10-link-time-specialization.md | 258 | ||||
| -rw-r--r-- | docs/user-guide/toc.html | 12 |
4 files changed, 315 insertions, 46 deletions
diff --git a/docs/user-guide/08-compiling.md b/docs/user-guide/08-compiling.md index 1aca3071c..e0bf956e3 100644 --- a/docs/user-guide/08-compiling.md +++ b/docs/user-guide/08-compiling.md @@ -11,14 +11,14 @@ We will start with a discussion of the mental model that Slang uses for compilat Next we will cover the command-line Slang compiler, `slangc`, and how to use it to perform offline compilation. 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 +## 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 +### 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. @@ -27,7 +27,7 @@ If multiple source units are specified as part of the same compile, they will be 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 +### 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. @@ -57,12 +57,12 @@ A modernized codebase that uses modular `include` feature as documented in [Modu The result of compiling a translation unit is a module in Slang's internal intermediate representation (IR). The compiled module can then be serialized to a `.slang-module` binary file and loaded/imported just as `.slang` files. -## Entry Points +### 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 +### 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 directly documents intention and makes source code less dependent on external compiler configuration options. @@ -72,7 +72,7 @@ Developers are encouraged to use this model because it directly documents intent 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 +### 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. @@ -80,7 +80,7 @@ Similarly, each entry point may define zero or more entry-point `uniform` shader 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 +### 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: @@ -104,7 +104,7 @@ When using multiple targets at a time, it is important to understand the distinc > 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 +### 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. @@ -120,7 +120,7 @@ For the purposes of the compilation model it is important to note that the layou An important design choice in Slang is give the user of the compiler control over these choices. -## Composition +### 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_. @@ -130,26 +130,25 @@ A _composite_ component type is formed from a list of other component types (for 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 invoke the linking step to resolve all cross module refeerences. -## Linking +### Linking A user-composed program may have transitive module dependencies and cross references between module boundaries. The linking step in Slang is to resolve all the cross references in the IR and produce a new self-contained IR module that has everything needed for target code generation. The user will have an opportunity to specialize precompiled modules or provide additional compiler backend options at the linking step. -## Kernels +### Kernels Once a program is linked, the user can request generation of the _kernel_ 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 shader code can result in different layouts, which leads to different kernels being required. -Command-Line Compilation with `slangc` --------------------------------------- +## 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 +### Example Here we will repeat the example used in the [Getting Started](01-get-started.md) chapter. Given the following Slang code: @@ -175,7 +174,7 @@ we can compile the `computeMain()` entry point to SPIR-V using the following com slangc hello-world.slang -entry computeMain -target spirv -o hello-world.spv ``` -## Source Files and Translation Units +### 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. @@ -189,7 +188,7 @@ If multiple source files are passed to `slangc`, they will be grouped into trans * Each `.slang-module` file forms its own translation unit. -## Entry Points +### 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`. @@ -201,7 +200,7 @@ In code that does not use `[shader(...)]` attributes, a `-entry` option should b slangc hello-world.slang -entry computeMain -stage compute -o hello-world.spv ``` -## Targets +### 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`. @@ -214,12 +213,12 @@ Slang provides two main kinds of profiles for use with `slangc`: * GLSL versions can be used as profile with names like `glsl_430` and `glsl_460` -## Kernels +### 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 +### 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. @@ -240,7 +239,7 @@ 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 +### Additional Options The main other options are: @@ -252,7 +251,7 @@ The main other options are: * `-O<level>` can be used to control optimization levels when the Slang compiler invokes downstream code generator -## Convenience Features +### Convenience Features The `slangc` compiler provides a few conveniences for command-line compilation: @@ -262,7 +261,7 @@ The `slangc` compiler provides a few conveniences for command-line compilation: * 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. -## Precompiled Modules +### Precompiled Modules You can compile a `.slang` file into a binary IR module. For example, given the following source: @@ -282,11 +281,11 @@ This allows you to deploy just the `library.slang-module` file to users of the l import library; ``` -## More Options +### More Options See [slangc command line reference](https://github.com/shader-slang/slang/blob/master/docs/command-line-slangc-reference.md) for a complete list of compiler options supported by the `slangc` tool. -## Limitations +### 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. @@ -298,13 +297,12 @@ Notable features that Slang supports which cannot be accessed from `slangc` incl Applications that more control over compilation are encouraged to use the C++ compilation API described in the next section. -Using the Compilation API -------------------------- +## 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 +### "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. @@ -316,7 +314,7 @@ Application code is expected to correctly maintain the reference counts of `ISla 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 +### 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()`: @@ -333,7 +331,7 @@ The standard library can take a significant amount of time to load, so applicati > 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 compiles with a distinct global session. -## Creating a 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: @@ -401,9 +399,9 @@ struct SessionDesc ``` The user can specify a set of commonly used compiler options directly in the `SessionDesc` struct, such as `searchPath` and `preprocessMacros`. Additional compiler options can be specified via the `compilerOptionEntries` field, which is an array of `CompilerOptionEntry` that defines a key-value -pair of a compiler option setting, see the [Compiler Options](#compileroptions) section. +pair of a compiler option setting, see the [Compiler Options](#compiler-options) section. -### Targets +#### 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. @@ -434,7 +432,7 @@ sessionDesc.targets = &targetDesc; sessionDesc.targetCount = 1; ``` -### Search Paths +#### 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*`: @@ -445,7 +443,7 @@ sessionDesc.searchPaths = searchPaths; sessionDesc.searchPathCount = 1; ``` -### Pre-Defined Macros +#### 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: @@ -456,12 +454,12 @@ sessionDesc.preprocessorMacros = &fancyFlag; sessionDesc.preprocessorMacroCount = 1; ``` -### More Options +#### More Options You can specify other compiler options for the session or for a specific target through the `compilerOptionEntries` and `compilerOptionEntryCount` fields -of the `SessionDesc` or `TargetDesc` structures. See the [Compiler Options](#compileroptions) section for more details on how to encode such an array. +of the `SessionDesc` or `TargetDesc` structures. See the [Compiler Options](#compiler-options) section for more details on how to encode such an array. -## Loading a Module +### Loading a Module The simplest way to load code into a session is with `ISession::loadModule()`: @@ -475,7 +473,7 @@ The session will search for a matching module (usually in a file called `MyShade 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 +### 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. @@ -503,7 +501,7 @@ if(diagnostics) > #### Note #### > The `slang::IBlob` interface is binary-compatible with the `ID3D10Blob` and `ID3DBlob` interfaces used by some Direct3D compilation APIs. -## Entry Points +### 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: @@ -522,7 +520,7 @@ Slang::ComPtr<IEntryPoint> computeEntryPoint; module->findEntryPointByName("myComputeMain", computeEntryPoint.writeRef()); ``` -## Composition +### 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. @@ -540,7 +538,7 @@ As discussed earlier in this chapter, the composition operation serves two impor 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 +### 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()`: @@ -563,7 +561,7 @@ The details of how Slang computes layout, what guarantees it makes, and how to i 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. -## Linking +### Linking Before generating code, you must link the program to resolve all cross-module references. This can be done by calling `IComponentType::link` or `IComponentType::linkWithOptions` if you wish to specify additional compiler options for the program. @@ -574,9 +572,12 @@ Slang::ComPtr<ISlangBlob> diagnosticBlob; program->link(linkedProgram.writeRef(), diagnosticBlob.writeRef()); ``` +The linking step is also used to perform link-time specialization, which is a recommended approach for shader specialization +compared to preprocessor based specialization. Please see [Link-time Specialization and Precompiled Modules](link-time-specialization) for more details. + Any diagnostic messages related to linking (for example, if an external symbol cannot be resolved) will be written to `diagnosticBlob`. -## Kernel Code +### Kernel Code Given a linked `IComponentType`, an application can extract kernel code for one of its entry points using `IComponentType::getEntryPointCode()`: @@ -631,8 +632,8 @@ struct CompilerOptionValue The meaning of each integer or string value is dependent on the compiler option. The following table lists all available compiler options that can be set and meanings of their `CompilerOptionValue` encodings. -| CompilerOptionName | Description | -| ------------------ | ----------- | +|CompilerOptionName | Description | +|:------------------ |:----------- | | MacroDefine | Specifies a prepreocessor macro define entry. `stringValue0` encodes macro name, `stringValue1` encodes the macro value. | Include | Specifies an additional search path. `stringValue0` encodes the additional path. | | Language | Specifies the input language. `intValue0` encodes a value defined in `SlangSourceLanguage`. | diff --git a/docs/user-guide/09-targets.md b/docs/user-guide/09-targets.md index d6dfd4cf6..0b7845108 100644 --- a/docs/user-guide/09-targets.md +++ b/docs/user-guide/09-targets.md @@ -363,5 +363,3 @@ Summary This chapter has reviewed the main target platforms supported by the Slang compiler and runtime system. A key point to take away is that there is great variation in the capabilities of these systems. Even superficially similar graphics APIs have complicated differences in their parameter-passing mechanisms that must be accounted for by application programmers and GPU compilers. - -In the next chapter, we will discuss how the Slang compiler adapts to the different capabilities and rules of these platforms when laying out shader parameters in memory and then binding those parameters to the mechanisms defined by each platform. diff --git a/docs/user-guide/10-link-time-specialization.md b/docs/user-guide/10-link-time-specialization.md new file mode 100644 index 000000000..9f2fea969 --- /dev/null +++ b/docs/user-guide/10-link-time-specialization.md @@ -0,0 +1,258 @@ +--- +layout: user-guide +permalink: /user-guide/link-time-specialization +--- + +# Link-time Specialization and Module Precompilation + +Traditionally, graphics developers have been relying on the preprocesor defines to specialize their shader code for high-performance GPU execution. +While functioning systems can be built around preprocessor macros, overusing them leads to many problems: +- Long compilation time. With preprocessors defines, specialzation happens before parsing, which is a very early stage in the compilation flow. + This means that the compiler must redo almost all work from the scratch with every specialized variant, including parsing, type checking, IR generation + and optimization, even when two specialized variants only differ in one constant value. The lack of reuse of compiler front-end work between + different shader specializations contributes a significant portion to long shader compile times. +- Reduced code readability and maintainability. The compiler cannot enforce any structures on preprocessor macros and cannot offer static checks to + guarantee that the preprocessor macros are used in an intended way. Macros don't blend well with the native language syntax, which leads to less + readable code, mystic diagnostic messages when things go wrong, and suboptimal intellisense experience. +- Locked in with early specialization. Once the code is written using preprocessor macros for specialization, the application that uses the shader + code has no choice but to provide the macro values during shader compilation and always opt-in to static specialization. If the developer changes + their mind to move away from specialization, a lot of code needs to be rewritten. As a result, the application is locked out of opportunities to + take advantage of different design decisions or future hardware features that allow more efficient execution of non-specialized code. + +Slang approaches the problem of shader specialization by supporting generics as a first class feature that allow most specializable code to be +written in strongly typed code, and by allowing specialization to be triggered through link-time constants or types. + +As discussed in the [Compiling code with Slang](compiling) chapter, Slang provides a three-step compilation model: precompiling, linking and target code generation. +Assuming the user shader is implemented as three Slang modules: `a.slang`, `b.slang`, and `c.slang`, the user can precompile all three modules to binary IR and store +them as `a.slang-module`, `b.slang-module`, and `c.slang-module` in a complete offline process that is independent to any specialization arguments. +Next, these three IR modules are linked together to form a self-contained program that will then go through a set of compiler optimizations for target code generation. +Slang's compilation model allows specialization arguments, in the form of constants or types to be provided during linking. This means that specialization happens at +a much later stage of compilation, reusing all the work done during module precompilation. + +## Link-time Constants + +The simplest form of link time specialization is done through link-time constants. See the following code for an example. +```c++ +// main.slang + +// Define a constant whose value will be provided in another module at link time. +extern static const int kSampleCount; + +float sample(int index) {...} + +RWStructuredBuffer<float> output; +void main(uint tid : SV_DispatchThreadID) +{ + [ForceUnroll] + for (int i = 0; i < kSampleCount; i++) + output[tid] += sample(i); +} +``` +This code defines a compute shader that can be specialized with different constant values of `kSampleCount`. The `extern` modifier means that +`kSampleCount` is a constant whose value is not provided within the current module, but will be resolved during the linking step. +The `main.slang` file can be compiled offline into a binary IR module with the `slangc` tool: +``` +slangc main.slang -o main.slang-module +``` + +To specialize the code with a value of `kSampleCount`, the user can create another module that defines it: + +```c++ +// sample-count.slang +export static const int kSampleCount = 2; +``` + +This file can also be compiled separately: +``` +slangc sample-count.slang -o sample-count.slang-module +``` + +With these two modules precompiled, we can link them together to get our specialized code: +``` +slangc sample-count.slang-module main.slang-module -target hlsl -entry main -profile cs_6_0 -o main.hlsl +``` + +This process can also be done with Slang's compilation API as in the following code snippet: + +```c++ + +ComPtr<slang::ISession> slangSession = ...; +ComPtr<slang::IBlob> diagnosticsBlob; + +// Load the main module from file. +slang::IModule* mainModule = slangSession->loadModule("main.slang", diagnosticsBlob.writeRef()); + +// Load the specialization constant module from string. +const char* sampleCountSrc = R"(export static const int kSampleCount = 2;)"; +auto sampleCountModuleSrcBlob = UnownedRawBlob::create(sampleCountSrc, strlen(sampleCountSrc)); +slang::IModule* sampleCountModule = slangSession->loadModuleFromSource( + "sample-count", // module name + "sample-count.slang", // synthetic module path + sampleCountModuleSrcBlob); // module source content + +// Compose the modules and entry points. +ComPtr<slang::IEntryPoint> computeEntryPoint; +SLANG_RETURN_ON_FAIL( + module->findEntryPointByName(entryPointName, computeEntryPoint.writeRef())); + +std::vector<slang::IComponentType*> componentTypes; +componentTypes.push_back(mainModule); +componentTypes.push_back(computeEntryPoint); +componentTypes.push_back(sampleCountModule); + +ComPtr<slang::IComponentType> composedProgram; +SlangResult result = slangSession->createCompositeComponentType( + componentTypes.data(), + componentTypes.size(), + composedProgram.writeRef(), + diagnosticsBlob.writeRef()); + +// Link. +ComPtr<slang::IComponentType> linkedProgram; +composedProgram->link(linkedProgram.writeRef(), diagnosticsBlob.writeRef()); + +// Get compiled code. +ComPtr<slang::IBlob> compiledCode; +linkedProgram->getEntryPointCode(0, 0, compiledCode.writeRef(), diagnosticBlob.writeRef()); + +``` + +## Link-time Types + +In addition to constants, you can also define types that are specified at link-time. For example, given the following modules: + +```csharp +// common.slang +interface ISampler +{ + int getSampleCount(); + float sample(int index); +} +struct FooSampler : ISampler +{ + int getSampleCount() { return 1; } + float sample(int index) { return 0.0; } +} +struct BarSampler : ISampler +{ + int getSampleCount() { return 2; } + float sample(int index) { return index * 0.5; } +} +``` + +```csharp +// main.slang +import common; +extern struct Sampler : ISampler; + +RWStructuredBuffer<float> output; +void main(uint tid : SV_DispatchThreadID) +{ + Sampler sampler; + [ForceUnroll] + for (int i = 0; i < sampler.getSampleCount(); i++) + output[tid] += sampler.sample(i); +} +``` + +Again, we can separately compile these modules into binary forms independently with how they will be specialized. +To specialize the shader, we can author a third module that provides a definition for the `extern Sampler` type: + +```csharp +// sampler.slang +import common; +export struct Sampler : ISampler = FooSampler; +``` + +The `=` syntax is a syntacic sugar that expands to the following code: + +```csharp +export struct Sampler : ISampler +{ + FooSampler inner; + int getSampleCount() { return inner.getSampleCount(); } + float sample(int index) { return inner.sample(index); } +} +``` + +When all these three modules are linked, we will produce a specialized shader that uses the `FooSampler`. + +## Providing Default Settings + +When defining an `extern` symbol as a link-time constant or type, it is allowed to provide a default value for that constant or type. +When no other modules exists to `export` the same-named symbol, the default value will be used in the linked program. + +For example, the following code is considered complete at linking and can proceed to code generation without any issues: +```c++ +// main.slang + +// Provide a default value when no other modules are exporting the symbol. +extern static const int kSampleCount = 2; +// ... +void main(uint tid : SV_DispatchThreadID) +{ + [ForceUnroll] + for (int i = 0; i < kSampleCount; i++) + output[tid] += sample(i); +} +``` + +## Restrictions + +Unlike preprocessors, link-time constants and types can only be used in places where shader parameter layout cannot be +affected. This means that link-time constants and types are subject to the following restrictions: +- Link-time constants cannot be used to define array sizes. +- Link-time types are considered "incomplete" types. A struct or array type that has incomplete typed element is also an incomplete type. + Incomplete types cannot be used as `ConstantBuffer` or `ParameterBlock` element type, and cannot be used directly as the type of + a uniform variable. + +However it is allowed to use incomplete types as the element type of `StructuredBuffer` or `GLSLStorageBuffer`. + +## Using Precompiling Modules with the API + +In addition to using `slangc` for precompiling Slang modules, the `IModule` class provides a method to serialize itself to disk: + +```C++ +/// Get a serialized representation of the checked module. +SlangResult IModule::serialize(ISlangBlob** outSerializedBlob); + +/// Write the serialized representation of this module to a file. +SlangResult IModule::writeToFile(char const* fileName); +``` + +These functions will write only the module itself to a file, which excludes the modules that it includes. To write all imported +modules, you can use methods from the `ISession` class to enumerate all currently loaded modules (including transitively imported modules) +in the session: + +```c++ +SlangInt ISession::getLoadedModuleCount(); +IModule* ISession::getLoadedModule(SlangInt index); +``` + +Additionally, the `ISession` class also provides a function to query if a previously compiled module is still up-to-date with the current +Slang version, the compiler options in the session and the current content of the source files used to compile the module: + +```c++ +bool ISession::isBinaryModuleUpToDate( + const char* modulePath, + slang::IBlob* binaryModuleBlob); +``` + +If the compiler options or source files has been changed since the module was last compiled, the `isBinaryModuleUpToDate` will return false. + +The compiler can be setup to automatically use the precompiled modules when they exist and up-to-date. When loading a module, +either triggered via the `ISession::loadModule` call or via transitive `import`s in the modules being loaded, the compiler will look in the +search paths for a `.slang-module` file first. If it exists, it will load the precompiled module instead of compiling from the source. +If you wish the compiler to verify whether the `.slang-module` file is up-to-date before loading it, you can specify the `CompilerOptionName::UseUpToDateBinaryModule` to `1` +when creating the session. When this option is set, the compiler will verify the precompiled module is still update, and will recompile the module +from source if it is not up-to-date. + + +## Additional Remarks + +Link-time specialization is Slang's answer to compile-time performance and modularity issues associated with preprocessor +based shader specialization. By representing specializable settings as link-time constants or link-time types, we are able +to defer shader specialization to link time, allowing reuse of all the front-end compilation work that includes tokenization, +parsing, type checking, IR generation and validation. As Slang evolves to support more language features and as the user code +is growing to be more complex, the cost of front-end compilation will only increase over time. By using link-time specialization +on precompiled modules, an application can be completely isolated from any front-end compilation cost.
\ No newline at end of file diff --git a/docs/user-guide/toc.html b/docs/user-guide/toc.html index 9e8c6f57d..9b88c78ab 100644 --- a/docs/user-guide/toc.html +++ b/docs/user-guide/toc.html @@ -97,8 +97,10 @@ <li data-link="compiling"><span>Compiling Code with Slang</span> <ul class="toc_list"> <li data-link="compiling#concepts"><span>Concepts</span></li> +<li data-link="compiling#-concepts"><span>## Concepts</span></li> <li data-link="compiling#command-line-compilation-with-slangc"><span>Command-Line Compilation with `slangc`</span></li> <li data-link="compiling#using-the-compilation-api"><span>Using the Compilation API</span></li> +<li data-link="compiling#compiler-options"><span>Compiler Options</span></li> </ul> </li> <li data-link="targets"><span>Supported Compilation Targets</span> @@ -113,6 +115,16 @@ <li data-link="targets#summary"><span>Summary</span></li> </ul> </li> +<li data-link="targets"><span>Link-time Specialization and Module Precompilation</span> +<ul class="toc_list"> +<li data-link="targets#link-time-constants"><span>Link-time Constants</span></li> +<li data-link="targets#link-time-types"><span>Link-time Types</span></li> +<li data-link="targets#providing-default-settings"><span>Providing Default Settings</span></li> +<li data-link="targets#restrictions"><span>Restrictions</span></li> +<li data-link="targets#using-precompiling-modules-with-the-api"><span>Using Precompiling Modules with the API</span></li> +<li data-link="targets#additional-remarks"><span>Additional Remarks</span></li> +</ul> +</li> <li data-link="a1-special-topics"><span>Special Topics</span> <ul class="toc_list"> <li data-link="a1-01-matrix-layout"><span>Handling Matrix Layout Differences on Different Platforms</span> |
