# `tecs.gpu.passes`
The render passes and render targets a frame is drawn through.
A pass names the targets it reads and the targets it writes. This module owns
the declaration; the Rust backend owns the textures, the pipelines and the
submission. The declaration crosses in the frame packet, so there is one copy
of every pass and target name rather than one on each side of the boundary.
Passes run in declaration order rather than in a topological order. The order
of a deferred pipeline is a design decision, and a graph that quietly reorders
itself is harder to reason about than one that refuses to run, so a pass that
reads a target no earlier pass writes is rejected where it is declared.
```nupp
tecs.gpu.passes.declareTarget({name = "gameOverlay", format = "rgba8"})
tecs.gpu.passes.insertPassBefore("present", {
name = "gameOverlay",
inputs = {"scene"},
outputs = {"gameOverlay"},
})
```
The built-in deferred graph is declared when this module loads. Its target and
pass names are a compatibility surface: a game names one to place a pass of its
own beside it, so they keep their established spelling wherever the code that
declares them lives.
Targets are sized with the frame. A `scale` below one halves or quarters both
axes, which is what a target holding nothing sharp asks for. The backend owns
allocation and reuse: it reallocates a target only when the frame size or the
declaration changes, and a target no pass reads or writes is still allocated,
because a pass may be declared for it later.
One depth attachment at frame size is shared by every pass that asks for depth.
`depth` is reserved as an input name and reads that attachment; it is not a
declarable target.
The built-in graph declares the shadow and bloom passes whether or not
`tecs.gfx.lighting` has them switched on, and the frame packet's own flags are
what decide each frame. Declaring them conditionally would mean tearing the
graph down and rebuilding it when a game changes its tuning, which would take
every pass a game inserted with it; a backend skipping a pass whose flag is
clear costs nothing and keeps every name a game placed something beside valid
for the life of the process.
# Built-in scope
Custom passes supply WGSL defining `postprocess(uv: vec2) -> vec4`.
The backend supplies `scene`, `passSampler`, the declared `input0`, `input1`,
and subsequent textures, and `params.values`, four vectors of four scalar
parameters. A depth input is a `texture_depth_2d`. Use `setParameters` for
animated tuning; this updates a uniform without recompiling the pipeline.
A custom pass writes one color output, or the window when outputs is empty.
A pass without a shader uses its built-in body or only clears its outputs.
The Tiled subsystem owns map parsing, tilesets, edits and static TileChunks.
Its chunks and animated sprites draw through this render-pass graph.
Each explicit `tecs.gfx.View` runs this graph at its viewport resolution.
The renderer composites those results in view order. With no explicit views,
the active camera draws one full-frame view.
## Types
### `Clear` _type_
```nupp
type Clear = {
r: number,
g: number,
b: number,
a: number
}
```
A color a target or a pass clears to.
Every channel runs zero to one and must be finite.
### `DepthMode` _type_
```nupp
type DepthMode = "none" | "testWrite" | "test"
```
Says how a pass uses the shared depth attachment.
`none` attaches no depth, so nothing rejects a fragment and nothing is
written. `testWrite` is what geometry asks for. `test` rejects a fragment
against what geometry already wrote without writing itself, which is what
blended content that must sort against opaque geometry asks for.
### `Format` _type_
```nupp
type Format = "rgba8" | "rgba16f" | "r8" | "r16f"
```
Selects the pixel format the backend allocates a target in.
These identifiers reach the wire and a game's own declarations, so they are
a compatibility surface.
### `Pass` _record_
```nupp
record Pass
shader: string?
parameters: {number}
name: string
inputs: {string}
outputs: {string}
depth: DepthMode
depthClear: number?
load: boolean
clear: Clear?
end
```
One render pass, as the graph holds it.
#### Fields
##### `shader`
```nupp
shader: string?
```
Read-only. Supplies WGSL defining postprocess(uv), or nil for a built-in body.
##### `parameters`
```nupp
parameters: {number}
```
Read-only. Supplies up to sixteen scalar shader parameters.
##### `name`
```nupp
name: string
```
Read-only. Names the pass, unique within the graph.
##### `inputs`
```nupp
inputs: {string}
```
Read-only. Lists the targets this pass samples, in binding order. The
list is the graph's and a caller must not write to it.
##### `outputs`
```nupp
outputs: {string}
```
Read-only. Lists the targets this pass writes. An empty list renders to
the swapchain, which is how the final composite reaches the screen.
##### `depth`
```nupp
depth: DepthMode
```
Read-only. Reports how the pass uses the shared depth attachment.
##### `depthClear`
```nupp
depthClear: number?
```
Read-only. Reports the value the depth attachment is cleared to when
the pass begins, or nil to load what is already there. One is the far
plane.
##### `load`
```nupp
load: boolean
```
Read-only. Reports true when the pass loads every output rather than
clearing it, whatever the targets themselves declare.
##### `clear`
```nupp
clear: Clear?
```
Read-only. Reports the color this pass clears every output to, winning
over what the targets declare. Nil takes each target's own clear.
### `PassSpec` _type_
```nupp
type PassSpec = {
shader: string?,
parameters: {number}?,
name: string,
inputs: {string}?,
outputs: {string}?,
depth: DepthMode?,
depthClear: number?,
load: boolean?,
clear: Clear?
}
```
What a caller passes to `declarePass` or `insertPassBefore`.
The module copies every field and every list, so the tables a caller builds
are theirs to reuse. `inputs` names the targets the pass samples, in
binding order, and `tecs.gpu.passes.DEPTH` among them reads the shared
depth attachment. `outputs` names the targets it writes, and an omitted or
empty list renders to the swapchain. `depth` defaults to `"none"` and
`depthClear` omitted loads what is already there. `load` makes the pass
load every output rather than clear it, and `clear` overrides every
output's own clear with one color.
### `Target` _record_
```nupp
record Target
name: string
format: Format
scale: number
clear: Clear?
end
```
A target the backend allocates, sizes with the frame, and owns.
#### Fields
##### `name`
```nupp
name: string
```
Read-only. Names the target for `inputs`, `outputs`, and `formatOf`.
##### `format`
```nupp
format: Format
```
Read-only. Reports the pixel format the backend allocates.
##### `scale`
```nupp
scale: number
```
Read-only. Reports the size relative to the frame, above zero and at
most one. A half halves each axis.
##### `clear`
```nupp
clear: Clear?
```
Read-only. Reports the color a pass writing this target clears it to,
or nil when a pass loads what is already there.
### `TargetSpec` _type_
```nupp
type TargetSpec = {
name: string,
format: Format?,
scale: number?,
clear: Clear?
}
```
What a caller passes to `declareTarget`.
The module copies every field, so the table a caller builds is theirs to
reuse. `format` defaults to `"rgba8"` and `scale` to one, and an omitted
`clear` loads what is already in the target.
## Functions
### `declarePass` _function_
```nupp
function declarePass(spec: PassSpec): nil
```
Declares a pass that runs after every pass declared so far.
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `spec` | `PassSpec` | the pass to declare, copied rather than retained |
#### Returns
| Type | Description |
| --- | --- |
| `nil` | |
#### Raises
- when the name is already declared, when an input is undeclared or is not written by an earlier pass, when an output is undeclared, or when a pass using depth writes a target below frame scale
### `declareTarget` _function_
```nupp
function declareTarget(spec: TargetSpec): nil
```
Declares a target the backend allocates and owns.
Nothing is allocated here. The backend sizes the target on the first frame
after the declaration reaches it.
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `spec` | `TargetSpec` | the target to declare, copied rather than retained |
#### Returns
| Type | Description |
| --- | --- |
| `nil` | |
#### Raises
- when the name is already declared, when it is the reserved depth name, when the format is unknown, or when the scale is outside zero exclusive to one inclusive
### `formatOf` _function_
```nupp
function formatOf(name: string): Format?
```
Returns the format a target was declared with.
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `name` | `string` | a declared target's name |
#### Returns
| Type | Description |
| --- | --- |
| `Format?` | the format, or nil when nothing carries that name |
### `insertPassBefore` _function_
```nupp
function insertPassBefore(before: string, spec: PassSpec): nil
```
Declares a pass that runs immediately before an already declared one.
This is how a game places a pass of its own at a named seam without knowing
what else the graph holds.
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `before` | `string` | the name of the declared pass this one runs before |
| `spec` | `PassSpec` | the pass to declare, copied rather than retained |
#### Returns
| Type | Description |
| --- | --- |
| `nil` | |
#### Raises
- when no pass carries the `before` name, and for every reason `declarePass` raises
### `passes` _function_
```nupp
function passes(): {Pass}
```
Returns the declared passes in execution order.
#### Returns
| Type | Description |
| --- | --- |
| `{Pass}` | the graph's own list, which a caller reads and must not write |
### `reset` _function_
```nupp
function reset(): nil
```
Forgets every declaration and declares the built-in graph again.
A test uses this to start from the engine's own graph. It raises the
revision, so a backend rebuilds rather than keeping what it held.
#### Returns
| Type | Description |
| --- | --- |
| `nil` | |
### `revision` _function_
```nupp
function revision(): integer
```
Returns how many declarations have been made.
The backend rebuilds its graph when this changes, so it counts every
declaration rather than describing the graph's contents.
#### Returns
| Type | Description |
| --- | --- |
| `integer` | a value that only ever increases within one process |
### `section` _function_
```nupp
function section(): string
```
Encodes the graph for the frame packet.
The encoding is cached and rebuilt only when a declaration changes it, so a
steady graph costs one string for the life of the process.
The section holds a name table, then the targets, then the passes. Names
appear once and every record indexes into the table, because a target name
appears once as a declaration and again in every pass that reads or writes
it.
| Offset | Type | Field |
| ------ | ----- | ---------------------------------------------------- |
| 0 | `u32` | `nameCount` |
| 4 | `u32` | `nameBytes`, the padded length of the name blob |
| 8 | bytes | `nameCount` NUL-terminated names, padded to four |
| ... | `u32` | `targetCount` |
| ... | ... | `targetCount` records of 32 bytes |
| ... | `u32` | `passCount` |
| ... | ... | `passCount` variable-length records |
A target record is `nameIndex`, `format`, `scale`, `clearPresent`, and four
clear channels. A pass record is `nameIndex`, `depthMode`,
`depthClearPresent`, `depthClear`, `clearMode`, four clear channels,
`inputCount`, `outputCount`, then that many name indices of each. Name
indices count from zero.
#### Returns
| Type | Description |
| --- | --- |
| `string` | a host-endian section the caller owns |
### `setParameters` _function_
```nupp
function setParameters(name: string, values: {number}): nil
```
Changes one pass's uniform parameters without recompiling its pipeline.
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `name` | `string` | The caller supplies the existing custom pass name. |
| `values` | `{number}` | The caller supplies at most sixteen finite scalars; omitted lanes are zero. |
#### Returns
| Type | Description |
| --- | --- |
| `nil` | |
#### Raises
- When the pass has no custom shader or any scalar is invalid.
### `setShader` _function_
```nupp
function setShader(name: string, source: string): nil
```
Replaces a pass's custom WGSL body while preserving its inputs and outputs.
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `name` | `string` | The caller supplies an existing pass name. |
| `source` | `string` | The caller supplies WGSL defining postprocess(uv: vec2) -> vec4. |
#### Returns
| Type | Description |
| --- | --- |
| `nil` | |
#### Raises
- When the source is empty, too large, or the pass writes multiple outputs.
### `targets` _function_
```nupp
function targets(): {Target}
```
Returns the declared targets in declaration order.
#### Returns
| Type | Description |
| --- | --- |
| `{Target}` | the graph's own list, which a caller reads and must not write |
## Values
### `DEPTH` _variable_
```nupp
const DEPTH: string
```
Names the shared depth attachment, which is not a declarable target.
A pass naming this as an input samples what an earlier depth-writing pass
produced. This string is a compatibility surface.