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.
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<f32>) -> vec4<f32>. 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.
Module contents
Types
| Type | Kind | Description |
|---|---|---|
Clear | type | A color a target or a pass clears to. |
DepthMode | type | Says how a pass uses the shared depth attachment. |
Format | type | Selects the pixel format the backend allocates a target in. |
Pass | record | One render pass, as the graph holds it. |
PassSpec | type | What a caller passes to declarePass or insertPassBefore. |
Target | record | A target the backend allocates, sizes with the frame, and owns. |
TargetSpec | type | What a caller passes to declareTarget. |
Functions
| Function | Kind | Description |
|---|---|---|
declarePass | function | Declares a pass that runs after every pass declared so far. |
declareTarget | function | Declares a target the backend allocates and owns. |
formatOf | function | Returns the format a target was declared with. |
insertPassBefore | function | Declares a pass that runs immediately before an already declared one. |
passes | function | Returns the declared passes in execution order. |
reset | function | Forgets every declaration and declares the built-in graph again. |
revision | function | Returns how many declarations have been made. |
section | function | Encodes the graph for the frame packet. |
setParameters | function | Changes one pass's uniform parameters without recompiling its pipeline. |
setShader | function | Replaces a pass's custom WGSL body while preserving its inputs and outputs. |
targets | function | Returns the declared targets in declaration order. |
Values
| Value | Kind | Description |
|---|---|---|
DEPTH | variable | Names the shared depth attachment, which is not a declarable target. |
Types#
Cleartype#
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.
DepthModetype#
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.
Formattype#
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.
Passrecord#
record Pass
shader: string?
parameters: {number}
name: string
inputs: {string}
outputs: {string}
depth: DepthMode
depthClear: number?
load: boolean
clear: Clear?
endOne render pass, as the graph holds it.
Fields
shader#
shader: string?Read-only. Supplies WGSL defining postprocess(uv), or nil for a built-in body.
inputs#
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#
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.
depthClear#
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#
load: booleanRead-only. Reports true when the pass loads every output rather than clearing it, whatever the targets themselves declare.
PassSpectype#
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.
Targetrecord#
A target the backend allocates, sizes with the frame, and owns.
Fields
scale#
scale: numberRead-only. Reports the size relative to the frame, above zero and at most one. A half halves each axis.
TargetSpectype#
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#
declarePassfunction#
function declarePass(spec: PassSpec): nilDeclares 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
declareTargetfunction#
function declareTarget(spec: TargetSpec): nilDeclares 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
formatOffunction#
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 |
insertPassBeforefunction#
function insertPassBefore(before: string, spec: PassSpec): nilDeclares 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
beforename, and for every reasondeclarePassraises
passesfunction#
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 |
resetfunction#
function reset(): nilForgets 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 |
revisionfunction#
function revision(): integerReturns 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 |
sectionfunction#
function section(): stringEncodes 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 |
setParametersfunction#
function setParameters(name: string, values: {number}): nilChanges 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.
setShaderfunction#
function setShader(name: string, source: string): nilReplaces 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 |
Returns
| Type | Description |
|---|---|
nil |
Raises
When the source is empty, too large, or the pass writes multiple outputs.
targetsfunction#
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#
DEPTHvariable#
const DEPTH: stringNames 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.