# `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.