summaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2021-05-04 12:53:27 -0700
committerGitHub <noreply@github.com>2021-05-04 12:53:27 -0700
commitdc571f1291f6b82b189a0db52c0468ae2fc7af4b (patch)
tree8d1cb0ab02f6b27a0900aeb6e4e3fcd3a20d5aa3 /docs
parenta342080a4d58a5a1a3597ac34b0335202ec7c435 (diff)
Update gfx getting started doc (#1832)
Diffstat (limited to 'docs')
-rw-r--r--docs/_layouts/user-guide.html5
-rw-r--r--docs/assets/css/style.scss172
-rw-r--r--docs/build_toc.ps112
-rw-r--r--docs/gfx-user-guide/01-getting-started.md202
-rw-r--r--docs/gfx-user-guide/build_toc.ps19
-rw-r--r--docs/gfx-user-guide/toc.html4
-rw-r--r--docs/user-guide/03-convenience-features.md32
-rw-r--r--docs/user-guide/04-interfaces-generics.md80
-rw-r--r--docs/user-guide/build_toc.ps19
9 files changed, 306 insertions, 219 deletions
diff --git a/docs/_layouts/user-guide.html b/docs/_layouts/user-guide.html
index 9a776aadc..1a4be7030 100644
--- a/docs/_layouts/user-guide.html
+++ b/docs/_layouts/user-guide.html
@@ -52,7 +52,6 @@
position: fixed;
overflow-y: auto;
box-sizing: border-box;
- max-height: 100vh;
display: block;
}
@@ -100,7 +99,7 @@
}
.toc_span:hover
{
- color: #3030BE
+ color: #d5000d;
}
.tocIcon
{
@@ -138,6 +137,7 @@
#tocColumn {
width: 300px;
display: block;
+ box-sizing: border-box;
}
#rightColumn {
padding-left: 320px;
@@ -151,6 +151,7 @@
position: static;
display: none;
border-right-style: none;
+ box-sizing: content-box;
}
#tocInner {
padding: 10px;
diff --git a/docs/assets/css/style.scss b/docs/assets/css/style.scss
index c1b99c280..801ee5577 100644
--- a/docs/assets/css/style.scss
+++ b/docs/assets/css/style.scss
@@ -30,4 +30,174 @@ body {
#container
{
background:none;
-} \ No newline at end of file
+}
+
+
+
+.highlight .cm {
+ color: #148b04;
+}
+.highlight .cp {
+ color: #148b04;
+}
+.highlight .c1 {
+ color: #148b04;
+}
+.highlight .cs {
+ color: #148b04;
+}
+.highlight .c, .highlight .ch, .highlight .cd, .highlight .cpf {
+ color: #148b04;
+}
+.highlight .err {
+ color: #a61717;
+ background-color: #e3d2d2;
+}
+.highlight .gd {
+ color: #000000;
+ background-color: #ffdddd;
+}
+.highlight .ge {
+ color: #000000;
+ font-style: italic;
+}
+.highlight .gr {
+ color: #aa0000;
+}
+.highlight .gh {
+ color: #999999;
+}
+.highlight .gi {
+ color: #000000;
+ background-color: #ddffdd;
+}
+.highlight .go {
+ color: #888888;
+}
+.highlight .gp {
+ color: #555555;
+}
+.highlight .gu {
+ color: #aaaaaa;
+}
+.highlight .gt {
+ color: #aa0000;
+}
+.highlight .kc {
+ color: #1243d4;
+}
+.highlight .kd {
+ color: #1243d4;
+}
+.highlight .kn {
+ color: #1243d4;
+}
+.highlight .kp {
+ color: #1243d4;
+}
+.highlight .kr {
+ color: #1243d4;
+}
+.highlight .kt {
+ color: #1243d4;
+}
+.highlight .k, .highlight .kv {
+ color: #1243d4;
+}
+.highlight .m, .highlight .mb, .highlight .mx, .highlight .mi, .highlight .mf {
+ color: #7211c2;
+}
+.highlight .sa {
+ color: #000000;
+}
+.highlight .sb {
+ color: #d14;
+}
+.highlight .sc {
+ color: #d14;
+}
+.highlight .sd {
+ color: #d14;
+}
+.highlight .s2 {
+ color: #d14;
+}
+.highlight .se {
+ color: #d14;
+}
+.highlight .sh {
+ color: #d14;
+}
+.highlight .si {
+ color: #d14;
+}
+.highlight .sx {
+ color: #d14;
+}
+.highlight .sr {
+ color: #009926;
+}
+.highlight .s1 {
+ color: #d14;
+}
+.highlight .ss {
+ color: #990073;
+}
+.highlight .s, .highlight .dl {
+ color: #d14;
+}
+.highlight .na {
+ color: #008080;
+}
+.highlight .bp {
+ color: #999999;
+}
+.highlight .n{
+ color: black;
+}
+.highlight .nc {
+ color: #11abb9;
+}
+.highlight .nt {
+ color: #11abb9;
+}
+.highlight .vc {
+ color: #008080;
+}
+.highlight .vg {
+ color: #008080;
+}
+.highlight .vi {
+ color: #008080;
+}
+.highlight .nv, .highlight .vm {
+ color: #008080;
+}
+.highlight .ow {
+ color: #000000;
+}
+.highlight .o {
+ color: #000000;
+}
+.highlight .w {
+ color: #000000;
+}
+.highlight .p {color:#000000;}
+
+code
+{
+ background-color: initial;
+ border:none;
+}
+pre{
+ color: #000000;
+ background: #F8F8F8;
+}
+pre code {
+ color: #000000;
+ background-color: #F8F8F8;
+}
+.highlight
+{
+ background: #F8F8F8;
+}
diff --git a/docs/build_toc.ps1 b/docs/build_toc.ps1
new file mode 100644
index 000000000..ad727713d
--- /dev/null
+++ b/docs/build_toc.ps1
@@ -0,0 +1,12 @@
+$job = Start-Job -ArgumentList $PSScriptRoot -ScriptBlock {
+ Set-Location $args[0]
+ $code = (Get-Content -Raw -Path "scripts/Program.cs").ToString()
+ $assemblies = ("System.Core", "System.IO", "System.Collections")
+ Add-Type -ReferencedAssemblies $assemblies -TypeDefinition $code -Language CSharp
+ $path = Join-Path -Path $args[0] -ChildPath "user-guide"
+ [toc.Builder]::Run($path);
+ $path = Join-Path -Path $args[0] -ChildPath "gfx-user-guide"
+ [toc.Builder]::Run($path);
+}
+Wait-Job $job
+Receive-Job -Job $job
diff --git a/docs/gfx-user-guide/01-getting-started.md b/docs/gfx-user-guide/01-getting-started.md
index a6f6b241c..41b9738f6 100644
--- a/docs/gfx-user-guide/01-getting-started.md
+++ b/docs/gfx-user-guide/01-getting-started.md
@@ -31,7 +31,7 @@ Creating a GPU Device
To start using the graphics layer, create an `IDevice` object by calling `gfxCreateDevice`. The `IDevice` interface is the main entry-point to interact with the graphics layer. It represent GPU device context where all interactions with the GPU take place.
-```C++
+```cpp
#include "slang-gfx.h"
using namespace gfx;
@@ -56,7 +56,7 @@ The Slang Graphics Layer provides a debug layer that can be enabled to perform a
To receive diagnostic messages, you need to create a class that implements the `IDebugCallback` interface, and call `gfxSetDebugCallback` to provide the callback instance to the graphics layer. For example:
-```C++
+```cpp
struct MyDebugCallback : public IDebugCallback
{
virtual SLANG_NO_THROW void SLANG_MCALL handleMessage(
@@ -79,121 +79,43 @@ void initGfx()
}
```
-Creating a Pipeline State
----------------------------
-A pipeline state object encapsulates the shader program to execute on the GPU device, as well as other fix function states for graphics rendering. In this example, we will be compiling and runing a simple compute shader written in Slang. To do that we need to create a compute pipeline state from a Slang `IComponentType`. We refer the reader to the (Slang getting started tutorial)[../user-guide/01-getting-started.html] on how to create a Slang `IComponentType` from a shader file. The following source loads a shader from `hello-world.slang` and create a compute pipeline state from it:
+Creating a Command Queue
+------------------------------
+A command queue is where the GPU device takes commands from the application to execute. To create a command queue, call `IDevice::createCommandQueue`.
+```cpp
+ICommandQueue* gQueue = nullptr;
-```C++
-void createComputePipelineFromShader(IPipelineState*& outPipelineState)
-{
- // First we need to create slang global session with work with the Slang API.
- ComPtr<slang::IGlobalSession> slangGlobalSession;
- RETURN_ON_FAIL(slang::createGlobalSession(slangGlobalSession.writeRef()));
-
- // Next we create a compilation session to generate SPIRV code from Slang source.
- slang::SessionDesc sessionDesc = {};
- slang::TargetDesc targetDesc = {};
- targetDesc.format = SLANG_SPIRV;
- targetDesc.profile = slangGlobalSession->findProfile("glsl440");
- sessionDesc.targetCount = 1;
- sessionDesc.targets = &targetDesc;
-
- ComPtr<slang::ISession> session;
- RETURN_ON_FAIL(slangGlobalSession->createSession(sessionDesc, session.writeRef()));
-
- // Once the session has been obtained, we can start loading code into it.
- //
- // The simplest way to load code is by calling `loadModule` with the name of a Slang
- // module. A call to `loadModule("hello-world")` will behave more or less as if you
- // wrote:
- //
- // import hello_world;
- //
- // In a Slang shader file. The compiler will use its search paths to try to locate
- // `hello-world.slang`, then compile and load that file. If a matching module had
- // already been loaded previously, that would be used directly.
- slang::IModule* slangModule = nullptr;
- {
- ComPtr<slang::IBlob> diagnosticBlob;
- slangModule = session->loadModule("hello-world", diagnosticBlob.writeRef());
- diagnoseIfNeeded(diagnosticBlob);
- if (!slangModule)
- return -1;
- }
+ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics};
+device->createCommandQueue(queueDesc, &gQueue);
+```
- // Loading the `hello-world` module will compile and check all the shader code in it,
- // including the shader entry points we want to use. Now that the module is loaded
- // we can look up those entry points by name.
- //
- // Note: If you are using this `loadModule` approach to load your shader code it is
- // important to tag your entry point functions with the `[shader("...")]` attribute
- // (e.g., `[shader("compute")] void computeMain(...)`). Without that information there
- // is no umambiguous way for the compiler to know which functions represent entry
- // points when it parses your code via `loadModule()`.
- //
- ComPtr<slang::IEntryPoint> entryPoint;
- slangModule->findEntryPointByName("computeMain", entryPoint.writeRef());
-
- // At this point we have a few different Slang API objects that represent
- // pieces of our code: `module`, `vertexEntryPoint`, and `fragmentEntryPoint`.
- //
- // A single Slang module could contain many different entry points (e.g.,
- // four vertex entry points, three fragment entry points, and two compute
- // shaders), and before we try to generate output code for our target API
- // we need to identify which entry points we plan to use together.
- //
- // Modules and entry points are both examples of *component types* in the
- // Slang API. The API also provides a way to build a *composite* out of
- // other pieces, and that is what we are going to do with our module
- // and entry points.
- //
- Slang::List<slang::IComponentType*> componentTypes;
- componentTypes.add(slangModule);
- componentTypes.add(entryPoint);
-
- // Actually creating the composite component type is a single operation
- // on the Slang session, but the operation could potentially fail if
- // something about the composite was invalid (e.g., you are trying to
- // combine multiple copies of the same module), so we need to deal
- // with the possibility of diagnostic output.
- //
- ComPtr<slang::IComponentType> composedProgram;
- {
- ComPtr<slang::IBlob> diagnosticsBlob;
- SlangResult result = session->createCompositeComponentType(
- componentTypes.getBuffer(),
- componentTypes.getCount(),
- composedProgram.writeRef(),
- diagnosticsBlob.writeRef());
- diagnoseIfNeeded(diagnosticsBlob);
- RETURN_ON_FAIL(result);
- }
+Allocating a Command Buffer
+------------------------------
+A command buffer is treated as a _transient_ resource by the graphics layer. A transient resource is required by the GPU during execution of a task, and are no longer needed when the execution has completed. Slang graphics layer provides an `ITransientResourceHeap` object to efficiently manage the life cycle of transient resources. In order to allocate a command buffer, we need to create an `ITransientResourceHeap` object first by calling `IDevice::createTransientResourceHeap`.
- // Now we have obtained the `IComponentType` that represents the compute
- // kernel, we can use it to create a `IShaderProgram` object in the graphics
- // layer.
- IShaderProgram* shaderProgram = nullptr;
- IShaderProgram::Desc programDesc = {};
- programDesc.pipelineType = PipelineType::Compute;
- programDesc.slangProgram = componentType;
- gDevice->createShaderProgram(programDesc, &shaderProgram);
-
- // Create a compute pipeline state from `shaderProgram`.
- ComputePipelineStateDesc pipelineDesc = {};
- pipelineDesc.program = shaderProgram;
- gDevice->createComputePipelineState(pipelineDesc, &outPipelineState);
+```cpp
+ITransientResourceHeap* gTransientHeap;
- // Since we no longer need to use `shaderProgram` after creating
- // a pipeline state, we should release it to prevent memory leaks.
- shaderProgram->release();
-}
+ITransientResourceHeap::Desc transientHeapDesc = {};
+transientHeapDesc.constantBufferSize = 4096;
+device->createTransientResourceHeap(transientHeapDesc, &gTransientHeap);
+```
+
+With a `TransientResourceHeap`, we can call `createCommandBuffer` method to allocate a command buffer:
+
+```cpp
+ICommandBuffer* commandBuffer;
+gTransientHeap->createCommandBuffer(&commandBuffer);
```
+A user should regularly call `ITransientResourceHeap::synchronizeAndReset` to recycle all previously allocated transient resources. A standard practice is to create two `TransientResourceHeap`s in a double-buffered renderer, and alternate the transient heap on each frame to allocate command buffers and other transient resources. With this setup, the application can call `synchronizeAndReset` at start of each frame on the corresponding transient resource heap to make sure all transient resources are timely recycled.
+
Creating Buffer Resource
------------------------------
-We need to create the buffer resources used our `hello-world` shader as input and output. This can be done via `IDevice::createBufferResource` method.
-```C++
+We need to create the buffer resources used our `hello-world` shader as input and output. This can be done via `IDevice::createBufferResource` method. When creating a resource, the user must specify a resource state that the resource will be in by default, as well as all allowed resource states the resource can be in. Resource states in the graphics layer follows the same model of resource states in D3D12, and the user can also assume the same automatic resource promotion/demotion behavior in D3D12.
+
+```cpp
const int numberCount = 4;
float initialData[] = {0.0f, 1.0f, 2.0f, 3.0f};
IBufferResource::Desc bufferDesc = {};
@@ -210,37 +132,37 @@ SLANG_RETURN_ON_FAIL(device->createBufferResource(
&inputBuffer0));
```
-Creating a Command Queue
-------------------------------
-A command queue is where the GPU device takes commands from the application to execute. To create a command queue, call `IDevice::createCommandQueue`.
-```C++
-ICommandQueue* gQueue = nullptr;
-ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics};
-device->createCommandQueue(queueDesc, &gQueue);
-```
-
-Allocating a Command Buffer
-------------------------------
-A command buffer is treated as a _transient_ resource by the graphics layer. A transient resource is required by the GPU during execution of a task, and are no longer needed when the execution has completed. Slang graphics layer provides an `ITransientResourceHeap` object to efficiently manage the life cycle of transient resources. In order to allocate a command buffer, we need to create an `ITransientResourceHeap` object first by calling `IDevice::createTransientResourceHeap`.
-
-```C++
-ITransientResourceHeap* gTransientHeap;
+Creating a Pipeline State
+---------------------------
-ITransientResourceHeap::Desc transientHeapDesc = {};
-transientHeapDesc.constantBufferSize = 4096;
-device->createTransientResourceHeap(transientHeapDesc, &gTransientHeap);
-```
+A pipeline state object encapsulates the shader program to execute on the GPU device, as well as other fix function states for graphics rendering. In this example, we will be compiling and runing a simple compute shader written in Slang. To do that we need to create a compute pipeline state from a Slang `IComponentType`. We refer the reader to the (Slang getting started tutorial)[../user-guide/01-getting-started.html] on how to create a Slang `IComponentType` from a shader file. The following source creates a Graphics layer `IPipelineState` object from a shader module represented by a `slang::IComponentType` object:
-With a `TransientResourceHeap`, we can call `createCommandBuffer` method to allocate a command buffer:
+```cpp
+void createComputePipelineFromShader(
+ IComponentType* slangProgram,
+ IPipelineState*& outPipelineState)
+{
+ // The `IComponentType` parameter that represents the compute
+ // kernel, we can use it to create a `IShaderProgram` object in the graphics
+ // layer.
+ IShaderProgram* shaderProgram = nullptr;
+ IShaderProgram::Desc programDesc = {};
+ programDesc.pipelineType = PipelineType::Compute;
+ programDesc.slangProgram = slangProgram;
+ gDevice->createShaderProgram(programDesc, &shaderProgram);
+
+ // Create a compute pipeline state from `shaderProgram`.
+ ComputePipelineStateDesc pipelineDesc = {};
+ pipelineDesc.program = shaderProgram;
+ gDevice->createComputePipelineState(pipelineDesc, &outPipelineState);
-```C++
-ICommandBuffer* commandBuffer;
-gTransientHeap->createCommandBuffer(&commandBuffer);
+ // Since we no longer need to use `shaderProgram` after creating
+ // a pipeline state, we should release it to prevent memory leaks.
+ shaderProgram->release();
+}
```
-A user should regularly call `ITransientResourceHeap::synchronizeAndReset` to recycle all previously allocated transient resources. A standard practice is to create two `TransientResourceHeap`s in a double-buffered renderer, and alternate the transient heap on each frame to allocate command buffers and other transient resources. With this setup, the application can call `synchronizeAndReset` at start of each frame on the corresponding transient resource heap to make sure all transient resources are timely recycled.
-
Recording Commands to Run a Compute Shader
------------------------------------
@@ -251,19 +173,19 @@ set the compute pipeline state, bind shader parameters, and dispatch a kernel la
Since we are only using compute commands, we begin the recording by calling `ICommandBuffer::encodeComputeCommands`. This methods returns a transient `IComputeCommandEncoder` object for accepting actual compute commands.
-```C++
+```cpp
IComputeCommandEncoder* encoder = commandBuffer->encodeComputeCommands();
```
The first command is to bind the pipeline state we created earlier:
-```C++
+```cpp
IShaderObject* rootObject = encoder->bindPipeline(pipelineState);
```
Binding a pipeline state yields a transient `IShaderObject` object. We can use the `IShaderObject` instance to bind shader parameters. For the `hello-world` shader, we need to bind three parameters: `buffer0`, `buffer1` and `result`.
-```C++
+```cpp
// Create a resource view for buffer0.
IBufferView* buffer0View;
{
@@ -303,7 +225,7 @@ rootObject->setResource(ShaderOffset{0,2,0}, resultView);
After binding all shader parameters, we can now dispatch the kernel:
-```C++
+```cpp
encoder->dispatchCompute(1, 1, 1);
```
@@ -313,13 +235,13 @@ encoder->dispatchCompute(1, 1, 1);
When we are done recording commands, we need to close the command encoder and the command buffer.
-```C++
+```cpp
encoder->endEncoding();
commandBuffer->close();
```
Now we are ready to submit the command buffer to the command queue, and wait for the GPU execution to finish.
-```C++
+```cpp
gQueue->executeCommandBuffer(commandBuffer);
gQueue->wait();
```
@@ -329,7 +251,7 @@ Cleaning Up
At the end of our example, we need to make sure all created objects are released by calling the `release` method:
-```C++
+```cpp
commandBuffer->release();
gQueue->release();
gTransientResourceHeap->release();
diff --git a/docs/gfx-user-guide/build_toc.ps1 b/docs/gfx-user-guide/build_toc.ps1
deleted file mode 100644
index 567a73988..000000000
--- a/docs/gfx-user-guide/build_toc.ps1
+++ /dev/null
@@ -1,9 +0,0 @@
-$job = Start-Job -ArgumentList $PSScriptRoot -ScriptBlock {
- Set-Location $args[0]
- $code = (Get-Content -Raw -Path "../scripts/Program.cs").ToString()
- $assemblies = ("System.Core", "System.IO", "System.Collections")
- Add-Type -ReferencedAssemblies $assemblies -TypeDefinition $code -Language CSharp
- [toc.Builder]::Run($args[0])
-}
-Wait-Job $job
-Receive-Job -Job $job
diff --git a/docs/gfx-user-guide/toc.html b/docs/gfx-user-guide/toc.html
index 197790b93..be64cca17 100644
--- a/docs/gfx-user-guide/toc.html
+++ b/docs/gfx-user-guide/toc.html
@@ -5,10 +5,10 @@
<li data-link="01-getting-started#installation"><span>Installation</span></li>
<li data-link="01-getting-started#creating-a-gpu-device"><span>Creating a GPU Device</span></li>
<li data-link="01-getting-started#enabling-the-debug-layer"><span>Enabling the Debug Layer</span></li>
-<li data-link="01-getting-started#creating-a-pipeline-state"><span>Creating a Pipeline State</span></li>
-<li data-link="01-getting-started#creating-buffer-resource"><span>Creating Buffer Resource</span></li>
<li data-link="01-getting-started#creating-a-command-queue"><span>Creating a Command Queue</span></li>
<li data-link="01-getting-started#allocating-a-command-buffer"><span>Allocating a Command Buffer</span></li>
+<li data-link="01-getting-started#creating-buffer-resource"><span>Creating Buffer Resource</span></li>
+<li data-link="01-getting-started#creating-a-pipeline-state"><span>Creating a Pipeline State</span></li>
<li data-link="01-getting-started#recording-commands-to-run-a-compute-shader"><span>Recording Commands</span></li>
<li data-link="01-getting-started#cleaning-up"><span>Cleaning Up</span></li>
</ul>
diff --git a/docs/user-guide/03-convenience-features.md b/docs/user-guide/03-convenience-features.md
index 06db6535b..57286dfb1 100644
--- a/docs/user-guide/03-convenience-features.md
+++ b/docs/user-guide/03-convenience-features.md
@@ -8,17 +8,17 @@ This topic covers a series of nice-to-have language features in Slang. These fea
## Type Inference in Variable Definitions
Slang supports automatic variable type inference:
-```C#
+```csharp
var a = 1; // OK, `a` is an `int`.
var b = float3(0, 1, 2); // OK, `b` is a `float3`.
```
Automatic type inference require an initialization expression to present. Without an initial value, the compiler is not able to infer the type of the variable. The following code will result a compiler error:
-```C#
+```csharp
var a; // Error, cannot infer the type of `a`.
```
You may use the `var` keyword to define a variable in a modern syntax:
-```C#
+```csharp
var a : int = 1; // OK.
var b : int; // OK.
```
@@ -107,7 +107,7 @@ void test()
## 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#
+```csharp
struct MyType
{
uint flag;
@@ -122,7 +122,7 @@ struct MyType
Or equivalently in a "modern" syntax:
-```C#
+```csharp
struct MyType
{
uint flag;
@@ -136,7 +136,7 @@ struct MyType
```
You may also use an explicit parameter for the setter method:
-```C#
+```csharp
property uint highBits
{
set(uint x) { flag = (flag & 0xFF) + (x << 16); }
@@ -156,7 +156,7 @@ property uint highBits
Slang supports defining initializers in `struct` types. You can write:
-```C#
+```csharp
struct MyType
{
int myVal;
@@ -168,18 +168,18 @@ struct MyType
```
You can use an initializer to construct a new instance by using the type name in a function call expression:
-```C#
+```csharp
MyType instance = MyType(1,2); // instance.myVal is 3.
```
You may also use C++ style initializer list to invoke an initializer:
-```C#
+```csharp
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#
+```csharp
struct MyType
{
int myVal;
@@ -199,7 +199,7 @@ int test()
## Operator Overloading
Slang allows defining operator overloads as global methods:
-```C#
+```csharp
struct MyType
{
int val;
@@ -224,7 +224,7 @@ Slang currently supports overloading the following operators: `+`, `-`, `*`, `/`
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#
+```csharp
struct Base
{
int a;
@@ -243,7 +243,7 @@ void test()
```
A derived type can be implicitly casted to its base type:
-```C#
+```csharp
void acceptBase(Base b) { ... }
void test()
{
@@ -263,7 +263,7 @@ Extensions
--------------------
Slang allows defining additional members for a type outside its initial definition. For example, suppose we already have a type defined:
-```C#
+```csharp
struct MyType
{
int field;
@@ -272,7 +272,7 @@ struct MyType
```
You can extend `MyType` with new members:
-```C#
+```csharp
extension MyType
{
float newField;
@@ -282,7 +282,7 @@ extension MyType
All locations that sees the definition of the `extension` can access the new members:
-```C#
+```csharp
void test()
{
MyType t;
diff --git a/docs/user-guide/04-interfaces-generics.md b/docs/user-guide/04-interfaces-generics.md
index ec79daad8..45273618c 100644
--- a/docs/user-guide/04-interfaces-generics.md
+++ b/docs/user-guide/04-interfaces-generics.md
@@ -11,7 +11,7 @@ Interfaces
----------
Interfaces are used to define the methods and services a type should provide. You can define a interface as the following example:
-```C#
+```csharp
interface IFoo
{
int myMethod(float arg);
@@ -21,7 +21,7 @@ interface IFoo
Slang's syntax for defining interfaces are similar to `interface`s in C# and `protocal`s in Swift. In this example, the `IFoo` interface establishes a contract that any type conforming to this interface must provide a method named `myMethod` that accepts a `float` argument and returns an `int` value.
A `struct` type may declare its conformance to an `interface` via the following syntax:
-```C#
+```csharp
struct MyType : IFoo
{
int myMethod(float arg)
@@ -33,7 +33,7 @@ struct MyType : IFoo
By declaring the conformance to `IFoo`, the definition of `MyType` must include a method named `myMethod` with a matching signature to that defined in the `IFoo` interface to satisfy the declared conformance. If a type misses any methods required by the interface, the Slang compiler will generate an error message.
A `struct` type may declare multiple interface conformances:
-```C#
+```csharp
interface IBar { uint myMethod2(uint2 x); }
struct MyType : IFoo, IBar
@@ -49,7 +49,7 @@ Generics
Generics can be used to eliminate duplicate code for shared logic that operates on different types. The following example shows how to define a generic method in Slang.
-```C#
+```csharp
int myGenericMethod<T: IFoo>(T arg)
{
return arg.myMethod(1.0);
@@ -59,7 +59,7 @@ int myGenericMethod<T: IFoo>(T arg)
The above listing defines a generic method named `myGenericMethod`, which accepts an argument that can be of any type `T` as long as `T` conforms to the `IFoo` interface. The `T` here is called a _generic type parameter_, and it is associated with an _type constraint_ that any type represented by `T` must conform to the interface `IFoo`.
The following listing shows how to invoke a generic method:
-```C#
+```csharp
MyType obj;
int a = myGenericMethod<MyType>(obj); // OK, explicit type argument
int b = myGenericMethod(obj); // OK, automatic type deduction
@@ -101,7 +101,7 @@ Slang supports many other constructs in addition to ordinary methods as a part o
### Properties
-```C#
+```csharp
interface IFoo
{
property int count {get; set;}
@@ -111,7 +111,7 @@ The above listing declares that any conforming type must define a property named
### Generic Methods
-```C#
+```csharp
interface IFoo
{
int compute<T:IBar>(T val);
@@ -121,7 +121,7 @@ The above listing declares that any conforming type must define a generic method
### Static Methods
-```C#
+```csharp
interface IFoo
{
static int compute(int val);
@@ -129,7 +129,7 @@ interface IFoo
```
The above listing declares that any conforming type must define a static method named `compute`. This allows the following generic method to pass type-checking:
-```C#
+```csharp
void f<T:IFoo>()
{
T.compute(5); // OK, T has a static method `compute`.
@@ -139,7 +139,7 @@ void f<T:IFoo>()
### `This` Type
You may use a special keyword `This` in interface definitions to refer to the type that is conforming to the interface. The following examples demonstrate a use of `This` type:
-```C#
+```csharp
interface IComparable
{
int comparesTo(This other);
@@ -158,21 +158,21 @@ In this example, the `IComparable` interface declares that any conforming type m
### Initializers
Consider a generic method that wants to create and initialize a new instance of generic type `T`:
-```C#
+```csharp
void f<T:IFoo>()
{
T obj = /*a newly initialized T*/
}
```
One way to implement this is to introduce a static method requirement in `IFoo`:
-```C#
+```csharp
interface IFoo
{
static This create();
}
```
With this interface definition, we can define `f` as following:
-```C#
+```csharp
void f<T:IFoo>()
{
T obj = T.create();
@@ -180,16 +180,16 @@ void f<T:IFoo>()
```
This solution works just fine, but it would be nicer if you can just write:
-```C#
+```csharp
T obj = T();
```
Or simply
-```C#
+```csharp
T obj;
```
And let the compiler invoke the default initializer defined in the type.
To enable this, you can include an initializer requirement in the interface definition:
-```C#
+```csharp
interface IFoo
{
__init();
@@ -197,7 +197,7 @@ interface IFoo
```
Initializers with parameters are supported as well. For example:
-```C#
+```csharp
interface IFoo
{
__init(int a, int b);
@@ -212,7 +212,7 @@ Associated Types
-------------------------
When writing code using interfaces and generics, there are some situations where the an interface method needs to return an object whose type is implementation-dependent. For example, consider the following `IFloatContainer` interface that represents a container of `float` values:
-```C#
+```csharp
// Represents a container of float values.
interface IFloatContainer
{
@@ -227,7 +227,7 @@ interface IFloatContainer
}
```
An implementation of the `IFloatContainer` interface may use different types of iterators. For example, an implementation that is simply an array of `float`s can expose `Iterator` as a simple integer index:
-```C#
+```csharp
struct ArrayFloatContainer : IFloatContainer
{
float content[10];
@@ -238,7 +238,7 @@ struct ArrayFloatContainer : IFloatContainer
}
```
On the other hand, an implementation that uses multiple buffers as the backing storage may use a more complex type to locate an element:
-```C#
+```csharp
// Exposes values in two `StructuredBuffer`s as a single container.
struct MultiArrayFloatContainer : IFloatContainer
{
@@ -258,7 +258,7 @@ struct MultiArrayFloatContainer : IFloatContainer
```
Ideally, a generic function that wishes to enumerate values in a `IFloatContainer` shouldn't need to care about the implementation details on what the concrete type of `Iterator` is, and we would like to be able to write the following:
-```C#
+```csharp
float sum<T:IFloatContainer>(T container)
{
float result = 0.0f;
@@ -275,7 +275,7 @@ Here the `sum` function simply wants to access all the elements and sum them up.
The problem is that the `IFloatContainer` interface definition requires methods like `begin()`, `end()` and `getElementAt()` to refer to a iterator type that is implementation dependent. How should the signature of these methods be defined in the interface? The answer is to use _associated types_.
In addition to constructs listed in the previous section, Slang also supports defining associated types in an `interface` definition. An associated type can be defined as following.
-```C#
+```csharp
// The interface for an iterator type.
interface IIterator
{
@@ -301,7 +301,7 @@ interface IFloatContainer
```
This `associatedtype` definition in `IFloatContainer` requires that all types conforming to this interface must also define a type in its scope named `Iterator`, and this iterator type must conform to the `IIterator` interface. An implementation to the `IFloatContainer` interface by using either a `typedef` declaration or a `struct` definition inside its scope to satisfy the associated type requirement. For example, the `ArrayFloatContainer` can be implemented as following:
-```C#
+```csharp
struct ArrayIterator : IIterator
{
uint index;
@@ -326,7 +326,7 @@ struct ArrayFloatContainer : IFloatContainer
```
Alternatively, you may also define the `Iterator` type directly inside a `struct` implementation, as in the following definition for `MultiArrayFloatContainer`:
-```C#
+```csharp
// Exposes values in two `StructuredBuffer`s as a single container.
struct MultiArrayFloatContainer : IFloatContainer
{
@@ -428,7 +428,7 @@ Generic Value Parameters
So far we have demonstrated generics with _type parameters_. Additionally, Slang also supports generic _value_ parameters.
The following listing shows an example of generic value parameters.
-```C#
+```csharp
struct Array<T, let N : int>
{
T arrayContent[N];
@@ -449,7 +449,7 @@ Interface-typed Values
So far we have been using interfaces as constraints to generic type parameters. For example, the following listing defines a generic function with a type parameter `TTransform` constrained by interface `ITransform`:
-```C#
+```csharp
interface ITransform
{
int compute(MyObject obj);
@@ -464,7 +464,7 @@ int apply<TTransform : ITransform>(TTransform transform, MyObject object)
While Slang's syntax for defining generic methods bears similarity to generics in C#/Java and templates in C++ and should be easy to users who are familiar with these languages, codebases that make heavy use of generics can quickly become verbose and difficult to read. To reduce the amount of boilerplate, Slang supports an alternate way to define the `apply` method by using the interface type `ITransform` as parameter type directly:
-```C#
+```csharp
// A method that is equivalent to `apply` but uses simpler syntax:
int apply_simple(ITransform transform, MyObject object)
{
@@ -475,7 +475,7 @@ int apply_simple(ITransform transform, MyObject object)
Instead of defining a generic type parameter `TTransform` and a method parameter `transform` that has `TTransform` type, you can simply define the same `apply` function like a normal method, with a `transform` parameter whose type is an interface. From the Slang compiler's view, `apply` and `apply_simple` will be compiled to the same target code.
In addition to parameters, Slang allows variables, and function return values to have an interface type as well:
-```C#
+```csharp
ITransform test(ITransform arg)
{
ITransform v = arg;
@@ -486,7 +486,7 @@ ITransform test(ITransform arg)
### Restrictions and Caveats
The Slang compiler always attempts to determine the actual type of an interface-typed value at compile time and specialize the code with the actual type. As long as the compiler can successfully determine the actual type, code that uses interface-typed values are equivalent to code written in the generics syntax. However, when interface types are used in function return values, the compiler will not be able to trivially propagate type information. For example:
-```C#
+```csharp
ITransform getTransform(int x)
{
if (x == 0)
@@ -503,7 +503,7 @@ ITransform getTransform(int x)
```
In this example, the actual type of the return value is dependent on the value of `x`, which may not be known at compile time. This means that the concrete type of the return value at invocation sites of `getTransform` may not be statically determinable. When the Slang compiler cannot infer the concrete type of an interface-type value, it will generate code that performs a dynamic dispatch based on the concrete type of the value at runtime, which may introduce performance overhead. Note that this behavior applies to function return values in the form of `out` parameters as well:
-```C#
+```csharp
void getTransform(int x, out ITransform transform)
{
if (x == 0)
@@ -521,7 +521,7 @@ void getTransform(int x, out ITransform transform)
This `getTransform` definition can also result in dynamic dispatch code since the type of `transform` may not be statically determinable.
When the compiler is generating dynamic dispatch code for interface-typed values, it requires the concrete type of the interface-typed value to be free of any opaque-typed fields (e.g. resources and buffer types). A compiler error will generated upon such attempts:
-```C#
+```csharp
struct MyTransform : ITransform
{
StructuredBuffer<int> buffer;
@@ -540,7 +540,7 @@ ITransform getTransform(int x)
```
Assigning different values to a mutable interface-typed variable also undermines the compiler's ability to statically determine the type of the variable, and is not supported by the Slang compiler today:
-```C#
+```csharp
void test(int x)
{
ITransform t = Type1Transform();
@@ -561,7 +561,7 @@ In the previous chapter, we introduced the `extension` feature that lets you def
`extensions` can be used to make an existing type conform to additional interfaces. Suppose we have an interface `IFoo` and a type `MyObject` that implements the interface:
-```C#
+```csharp
interface IFoo
{
int foo();
@@ -574,7 +574,7 @@ struct MyObject : IFoo
```
Now we introduce another interface, `IBar`:
-```C#
+```csharp
interface IBar
{
float bar();
@@ -582,7 +582,7 @@ interface IBar
```
We can define an `extension` to make `MyObject` conform to `IBar` as well:
-```C#
+```csharp
extension MyObject : IBar
{
float bar() { return 1.0f }
@@ -590,7 +590,7 @@ extension MyObject : IBar
```
With this extension, we can use `MyObject` in places that expects an `IBar` as well:
-```C#
+```csharp
void use(IBar b)
{
b.bar();
@@ -604,7 +604,7 @@ void test()
```
You may define more than one interface conformances in a single `extension`:
-```C#
+```csharp
interface IBar2
{
float bar2();
@@ -620,7 +620,7 @@ Extensions to Interfaces
-----------------------------
In addtion to extending ordinary types, you can define extensions on interfaces as well:
-```C#
+```csharp
// An example interface.
interface IFoo
{
@@ -643,7 +643,7 @@ int use(IFoo foo)
```
Although the syntax of above listing suggests that we are extending an interface with additional requirements, this interpretation does not make logical sense in many ways. Consider a type `MyType` that exists before the extension is defined:
-```C#
+```csharp
struct MyType : IFoo
{
int foo() { return 0; }
@@ -652,7 +652,7 @@ struct MyType : IFoo
If we extend the `IFoo` with new requirements, the existing `MyType` definition would become invalid since `MyType` no longer provides implementations to all interface requirements. Instead, what an `extension` on an interface `IFoo` means is that for all types that conforms to the `IFoo` interface and does not have a `bar` method defined, add a `bar` method defined in this extension to that type so that all `IFoo` typed values have a `bar` method defined. If a type already defines a matching `bar` method, then the existing method will always override the default method provided in the extension:
-```C#
+```csharp
interface IFoo
{
int foo();
diff --git a/docs/user-guide/build_toc.ps1 b/docs/user-guide/build_toc.ps1
deleted file mode 100644
index 567a73988..000000000
--- a/docs/user-guide/build_toc.ps1
+++ /dev/null
@@ -1,9 +0,0 @@
-$job = Start-Job -ArgumentList $PSScriptRoot -ScriptBlock {
- Set-Location $args[0]
- $code = (Get-Content -Raw -Path "../scripts/Program.cs").ToString()
- $assemblies = ("System.Core", "System.IO", "System.Collections")
- Add-Type -ReferencedAssemblies $assemblies -TypeDefinition $code -Language CSharp
- [toc.Builder]::Run($args[0])
-}
-Wait-Job $job
-Receive-Job -Job $job