1# Tint Architecture 2 3``` 4 ┏━━━━━━━━┓ ┏━━━━━━┓ 5 ┃ SPIR━V ┃ ┃ WGSL ┃ 6 ┗━━━━┃━━━┛ ┗━━━┃━━┛ 7 ▼ ▼ 8 ┏━━━━━━━━━┃━━━━━━━━━━━━━━━━━━━━━━━━━━━┃━━━━━━━━┓ 9 ┃ ┃ Reader ┃ ┃ 10 ┃ ┃ ┃ ┃ 11 ┃ ┏━━━━━━━┻━━━━━━┓ ┏━━━━━━┻━━━━━━┓ ┃ 12 ┃ ┃ SPIRV-Reader ┃ ┃ WGSL-Reader ┃ ┃ 13 ┃ ┗━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━━━━┛ ┃ 14 ┗━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┛ 15 ▼ 16 ┏━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━┓ 17 ┃ ProgramBuilder ┃ 18 ┃ (mutable) ┃ 19 ┏━━━━━━━━━━━━►┫ ┏━━━━━┓ ┏━━━━━━━┓ ┏━━━━━━━━━┓ ┃ 20 ┃ ┃ ┃ AST ┃ ┃ Types ┃ ┃ Symbols ┃ ┃ 21 ┃ ┃ ┗━━━━━┛ ┗━━━━━━━┛ ┗━━━━━━━━━┛ ┃ 22 ┃ ┗━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┛ 23 ┃ ▼ 24 ┃ ┌┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┃┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┐ 25 ▲ ┆ Build ▼ ┆ 26 ┏━━━┻━━━┓ ┆ ┏━━━━━━━━┻━━━━━━━━┓ ┆ 27 ┃ Clone ┃ ┆ ┃ Resolver ┃ ┆ 28 ┗━━━┳━━━┛ ┆ ┗━━━━━━━━━━━━━━━━━┛ ┆ 29 ▲ └┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┃┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┘ 30 ┃ ▼ 31 ┃ ┏━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━┓ 32 ┃ ┃ Program ┃ 33 ┃ ┃ (immutable) ┃ 34 ┣━━━━━━◄┫ ┏━━━━━┓ ┏━━━━━━━┓ ┏━━━━━━━━━━┓ ┏━━━━━━━━━┓ ┃ 35 ┃ ┃ ┃ AST ┃ ┃ Types ┃ ┃ Semantic ┃ ┃ Symbols ┃ ┃ 36 ┃ ┃ ┗━━━━━┛ ┗━━━━━━━┛ ┗━━━━━━━━━━┛ ┗━━━━━━━━━┛ ┃ 37 ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┛ 38 ▲ ▼ 39┏━━━━━┻━━━━━┓ ┃ ┏━━━━━━━━━━━┓ 40┃ Transform ┃◄━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━►┃ Inspector ┃ 41┗━━━━━━━━━━━┛ ┃ ┗━━━━━━━━━━━┛ 42 ▼ 43┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 44┃ Writer ┃ 45┃ ┃ 46┃ ┏━━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━┓ ┃ 47┃ ┃ SPIRV-Writer ┃ ┃ WGSL-Writer ┃ ┃ HLSL-Writer ┃ ┃ MSL-Writer ┃ ┃ 48┃ ┗━━━━━━━┳━━━━━━┛ ┗━━━━━━┳━━━━━━┛ ┗━━━━━━┳━━━━━━┛ ┗━━━━━━┳━━━━━┛ ┃ 49┗━━━━━━━━━┃━━━━━━━━━━━━━━━━━━┃━━━━━━━━━━━━━━━━━━┃━━━━━━━━━━━━━━━━━━┃━━━━━━━┛ 50 ▼ ▼ ▼ ▼ 51 ┏━━━━┻━━━┓ ┏━━━┻━━┓ ┏━━━┻━━┓ ┏━━┻━━┓ 52 ┃ SPIR-V ┃ ┃ WGSL ┃ ┃ HLSL ┃ ┃ MSL ┃ 53 ┗━━━━━━━━┛ ┗━━━━━━┛ ┗━━━━━━┛ ┗━━━━━┛ 54``` 55 56## Reader 57 58Readers are responsible for parsing a shader program and populating a 59`ProgramBuilder` with the parsed AST, type and symbol information. 60 61The WGSL reader is a recursive descent parser. It closely follows the WGSL 62grammar in the naming of the parse methods. 63 64## ProgramBuilder 65 66A `ProgramBuilder` is the primary interface to construct an immutable `Program`. 67There are a number of methods exposed which make creating of the `Program` 68simpler. A `ProgramBuilder` can only be used once, and must be discarded after 69the `Program` is constructed. 70 71A `Program` is built from the `ProgramBuilder` by `std::move()`ing the 72`ProgramBuilder` to a new `Program` object. When built, resolution is performed 73so the produced `Program` will contain all the needed semantic information. 74 75At any time before building the `Program`, `ProgramBuilder::IsValid()` may be 76called to ensure the AST is **structurally** correct. This checks that things 77like `if` statements have a condition and body attached. 78 79If further changes to the `Program` are needed (say via a `Transform`) then a 80new `ProgramBuilder` can be produced by cloning the `Program` into a new 81`ProgramBuilder`. 82 83Unlike `Program`s, `ProgramBuilder`s are not part of the public Tint API. 84 85## AST 86 87The Abstract Syntax Tree is a directed acyclic graph of `ast::Node`s which 88encode the syntactic structure of the WGSL program. 89 90The root of the AST is the `ast::Module` class which holds each of the declared 91functions, variables and user defined types (type aliases and structures). 92 93Each `ast::Node` represents a **single** part of the program's source, and so 94`ast::Node`s are not shared. 95 96The AST does not perform any verification of its content. For example, the 97`ast::StrideDecoration` node has numeric stride parameter, which is a count of 98the number of bytes from the start of one array element to the start of the 99next. The AST node itself does not constrain the set of stride values that you 100can set, aside from storing it as an unsigned integer. 101 102## Types 103 104Types are constructed during the Reader and resolution phases, and are 105held by the `Program` or `ProgramBuilder`. AST and semantic nodes can both 106reference types. 107 108Each `type::Type` node **uniquely** represents a particular spelling of a WGSL 109type within the program, so you can compare `type::Type*` pointers to check for 110equivalence of type expressions. 111For example, there is only one `type::Type` node for the `i32` type, no matter 112how many times it is mentioned in the source program. 113However, if `MyI32` is a type alias for `i32`, then they will have two different 114type nodes. 115 116## Semantic information 117 118Semantic information is held by `sem::Node`s which describe the program at 119a higher / more abstract level than the AST. This includes information such as 120the resolved type of each expression, the resolved overload of an intrinsic 121function call, and the module scoped variables used by each function. 122 123Semantic information is generated by the `Resolver` when the `Program` 124is built from a `ProgramBuilder`. 125 126The `sem::Info` class holds a map of `ast::Node`s to `sem::Node`s. 127This map is **many-to-one** - i.e. while a AST node might have a single 128corresponding semantic node, the reverse may not be true. For example: 129many `ast::IdentifierExpression` nodes may map to a single `sem::Variable`, 130and so the `sem::Variable` does not have a single corresponding 131`ast::Node`. 132 133Unlike `ast::Node`s, semantic nodes may not necessarily form a directed acyclic 134graph, and the semantic graph may contain diamonds. 135 136## Symbols 137 138Symbols represent a unique string identifier in the source program. These string 139identifiers are transformed into symbols within the `Reader`s. 140 141During the Writer phase, symbols may be emitted as strings using a `Namer`. 142A `Namer` may output the symbol in any form that preserves the uniqueness of 143that symbol. 144 145## Resolver 146 147The `Resolver` will automatically run when a `Program` is built. 148A `Resolver` creates the `Program`s semantic information by analyzing the 149`Program`s AST and type information. 150 151The `Resolver` will validate to make sure the generated `Program` is 152semantically valid. 153 154## Program 155 156A `Program` holds an immutable version of the information from the 157`ProgramBuilder` along with semantic information generated by the 158`Resolver`. 159 160Like `ProgramBuilder`, `Program::IsValid()` may be called to ensure the AST is 161structurally correct and semantically valid, and that the `Resolver` did not 162report any errors. 163 164Unlike the `ProgramBuilder`, a `Program` is fully immutable, and is part of the 165public Tint API. The immutable nature of `Program`s make these entirely safe 166to share between multiple threads without the use of synchronization primitives. 167 168## Inspector 169 170The inspectors job is to go through the `Program` and pull out various pieces of 171information. The information may be used to pass information into the downstream 172compilers (things like specialization constants) or may be used to pass into 173transforms to update the AST before generating the resulting code. 174 175The input `Program` to the inspector must be valid (pass validation). 176 177## Transforms 178 179There maybe various transforms we want to run over the `Program`. 180This is for things like Vertex Pulling or Robust Buffer Access. 181 182A transform operates by cloning the input `Program` into a new `ProgramBuilder`, 183applying the required changes, and then finally building and returning a new 184output `Program`. As the resolver is always run when a `Program` is built, 185Transforms will always emit a `Program` with semantic information. 186 187The input `Program` to a transform must be valid (pass validation). 188If the input `Program` of a transform is valid then the transform must guarantee 189that the output program is also valid. 190 191## Writers 192 193A writer is responsible for writing the `Program` in the target shader language. 194 195The input `Program` to a writer must be valid (pass validation). 196