# Root Signatures

```{toctree}
:hidden: true
```

## Overview

A root signature is used to describe what resources a shader needs access to
and how they're organized and bound in the pipeline. The DirectX Container
(DXContainer) contains a root signature part (RTS0), which stores this
information in a binary format. To assist with the construction of, and
interaction with, a root signature is represented as metadata
(`dx.rootsignatures` ) in the LLVM IR. The metadata can then be converted to
its binary form, as defined in
[llvm/include/llvm/llvm/Frontend/HLSL/RootSignatureMetadata.h](https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/Frontend/HLSL/RootSignatureMetadata.h).
This document serves as a reference for the metadata representation of a root
signature for users to interface with.

## Metadata Representation

Consider the reference root signature, then the following sections describe the
metadata representation of this root signature and the corresponding operands.

```HLSL
RootFlags(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT),
RootConstants(b0, space = 1, num32Constants = 3),
CBV(b1, flags = 0),
StaticSampler(
  filter = FILTER_MIN_MAG_POINT_MIP_LINEAR,
  addressU = TEXTURE_ADDRESS_BORDER,
),
DescriptorTable(
  visibility = VISIBILITY_ALL,
  SRV(t0, flags = DATA_STATIC_WHILE_SET_AT_EXECUTE),
  UAV(
    numDescriptors = 5, u1, space = 10, offset = 5,
    flags = DATA_VOLATILE
  )
)
```

:::{note}
A root signature does not necessarily have a unique metadata representation.
Futher, a malformed root signature can be represented in the metadata format,
(eg. mixing Sampler and non-Sampler descriptor ranges), and so it is the
user's responsibility to verify that it is a well-formed root signature.
:::

## Named Root Signature Table

```LLVM
!dx.rootsignatures = !{!0}
```

A named metadata node, `` dx.rootsignatures` `` is used to identify the root
signature table. The table itself is a list of references to function/root
signature pairs.

## Function/Root Signature Pair

```LLVM
!1 = !{ptr @main, !2, i32 2 }
```

The function/root signature associates a function (the first operand) with a
reference to a root signature (the second operand). The root signature version
(the third operand) used for validation logic and binary format follows.

## Root Signature

```LLVM
!2 = !{ !3, !4, !5, !6, !7 }
```

The root signature itself simply consists of a list of references to its root
signature elements.

## Root Signature Element

A root signature element is identified by the first operand, which is a string.
The following root signature elements are defined:

| Identifier String | Root Signature Element |
| ----------------- | ---------------------- |
| "RootFlags"       | Root Flags             |
| "RootConstants"   | Root Constants         |
| "RootCBV"         | Root Descriptor        |
| "RootSRV"         | Root Descriptor        |
| "RootUAV"         | Root Descriptor        |
| "StaticSampler"   | Static Sampler         |
| "DescriptorTable" | Descriptor Table       |

Below is listed the representation for each type of root signature element.

## Root Flags

```LLVM
!3 = { !"RootFlags", i32 1 }
```

| Description                                  | Type |
| -------------------------------------------- | ---- |
| [Root Signature Flags][root signature flags] | i32  |

## Root Constants

```LLVM
!4 = { !"RootConstants", i32 0, i32 1, i32 2, i32 3 }
```

| Description                            | Type |
| -------------------------------------- | ---- |
| [Shader Visibility][shader visibility] | i32  |
| Shader Register                        | i32  |
| Register Space                         | i32  |
| Number 32-bit Values                   | i32  |

## Root Descriptor

As noted in the table above, the first operand will denote the type of
root descriptor.

```LLVM
!5 = { !"RootCBV", i32 0, i32 1, i32 0, i32 0 }
```

| Description                                    | Type |
| ---------------------------------------------- | ---- |
| [Shader Visibility][shader visibility]         | i32  |
| Shader Register                                | i32  |
| Register Space                                 | i32  |
| [Root Descriptor Flags][root descriptor flags] | i32  |

## Static Sampler

```LLVM
!6 = !{ !"StaticSampler", i32 1, i32 4, ... }; remaining operands omitted for space
```

| Description                            | Type  |
| -------------------------------------- | ----- |
| [Filter][filter]                       | i32   |
| [AddressU][addressu]                   | i32   |
| [AddressV][addressv]                   | i32   |
| [AddressW][addressw]                   | i32   |
| MipLODBias                             | float |
| MaxAnisotropy                          | i32   |
| [ComparisonFunc][comparisonfunc]       | i32   |
| [BorderColor][bordercolor]             | i32   |
| MinLOD                                 | float |
| MaxLOD                                 | float |
| ShaderRegister                         | i32   |
| RegisterSpace                          | i32   |
| [Shader Visibility][shader visibility] | i32   |

## Descriptor Table

A descriptor table consists of a visibility and the remaining operands are a
list of references to its descriptor ranges.

:::{note}
The term Descriptor Table Clause is synonymous with Descriptor Range when
referencing the implementation details.
:::

```LLVM
!7 = { !"DescriptorTable", i32 0, !8, !9 }
```

| Description                            | Type             |
| -------------------------------------- | ---------------- |
| [Shader Visibility][shader visibility] | i32              |
| Descriptor Range Elements              | Descriptor Range |

## Descriptor Range

Similar to a root descriptor, the first operand will denote the type of
descriptor range. It is one of the following types:

- "CBV"
- "SRV"
- "UAV"
- "Sampler"

```LLVM
!8 = !{ !"SRV", i32 1, i32 0, i32 0, i32 -1, i32 4 }
!9 = !{ !"UAV", i32 5, i32 1, i32 10, i32 5, i32 2 }
```

| Description                                      | Type |
| ------------------------------------------------ | ---- |
| Number of Descriptors in Range                   | i32  |
| Shader Register                                  | i32  |
| Register Space                                   | i32  |
| [Offset][offset]                                 | i32  |
| [Descriptor Range Flags][descriptor range flags] | i32  |

[addressu]: https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_texture_address_mode
[addressv]: https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_texture_address_mode
[addressw]: https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_texture_address_mode
[bordercolor]: https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_static_border_color>
[comparisonfunc]: https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_comparison_func>
[descriptor range flags]: https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_descriptor_range_flags
[filter]: https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_filter
[offset]: https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ns-d3d12-d3d12_descriptor_range
[root descriptor flags]: https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_root_descriptor_flags
[root signature flags]: https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_root_signature_flags
[shader visibility]: https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_shader_visibility

