🧠Render Graph (Host-Defined)
Vulfram lets the host define a render graph using logical IDs. The core validates the graph, compiles an execution plan, and runs it each frame.
If the graph is missing or invalid, the core falls back to a safe default pipeline so rendering always continues.
1. Why a Host-Defined Graph
- Host control: you decide the pass order and dependencies.
- Logical IDs only: no GPU handles leak to the host.
- Reusable plans: the core compiles a plan from your graph and uses it each frame.
- Robust: invalid graphs use a fallback automatically.
2. Core Flow
- Host builds a graph using IDs and descriptors.
- Core validates and compiles a plan.
- Core runs the plan each frame.
- If validation fails and
fallback=true, the fallback plan is used.
3. Graph Structure (Host Payload)
Graph
| Field | Type | Description |
|---|---|---|
graphId |
LogicalId | Cache key for compiled plans |
nodes |
Node[] | Render nodes (passes) |
edges |
Edge[] | Dependencies between nodes |
resources |
Resource[] | Declared logical resources |
fallback |
bool | Use fallback if graph is invalid |
Node
| Field | Type | Description |
|---|---|---|
nodeId |
LogicalId | Node identifier |
passId |
string | Pass type (ex: "forward") |
inputs |
LogicalId[] | Resource IDs read by this node |
outputs |
LogicalId[] | Resource IDs written by this node |
params |
Map | Optional parameters (clear flags, etc.) |
Resource
| Field | Type | Description |
|---|---|---|
resId |
LogicalId | Resource identifier |
kind |
string | "texture", "buffer", "attachment" |
desc |
Map | Logical descriptor (format, size, usage) |
lifetime |
string | "frame" or "persistent" |
aliasGroup |
LogicalId? | Optional memory aliasing group |
Edge
| Field | Type | Description |
|---|---|---|
fromNodeId |
LogicalId | Dependency source |
toNodeId |
LogicalId | Dependency target |
reason |
string? | Optional hint (read/write ordering) |
LogicalId
Logical IDs can be strings or numbers. The core resolves them to internal handles for the active plan.
4. Minimal Example
json
{
"graphId": "main_render",
"nodes": [
{ "nodeId": "shadow_pass", "passId": "shadow", "inputs": [], "outputs": ["shadow_atlas"] },
{ "nodeId": "forward_pass", "passId": "forward", "inputs": ["shadow_atlas"], "outputs": ["hdr_color", "depth"] },
{ "nodeId": "compose_pass", "passId": "compose", "inputs": ["hdr_color"], "outputs": ["swapchain"] }
],
"edges": [
{ "fromNodeId": "shadow_pass", "toNodeId": "forward_pass" },
{ "fromNodeId": "forward_pass", "toNodeId": "compose_pass" }
],
"resources": [
{ "resId": "shadow_atlas", "kind": "texture", "desc": { "format": "depth24", "size": "shadow_res" }, "lifetime": "frame" },
{ "resId": "hdr_color", "kind": "texture", "desc": { "format": "rgba16f", "size": "screen" }, "lifetime": "frame" },
{ "resId": "depth", "kind": "texture", "desc": { "format": "depth24", "size": "screen" }, "lifetime": "frame" },
{ "resId": "swapchain", "kind": "attachment", "desc": { "format": "swapchain" }, "lifetime": "frame" }
],
"fallback": true
}
5. Validation Rules (Core)
- DAG only: no cycles allowed.
- Resources exist: inputs/outputs must be declared in
resources. - Pass compatibility:
passIdmust be a known core pass type.
If validation fails, the core uses the fallback graph if enabled.
6. Fallback Graph
The fallback graph is the default pipeline the engine can always execute. It typically looks like:
text
shadow -> forward -> compose
7. Performance Notes
- Alias groups: reserved for future memory reuse (currently not applied by the core).
- Frame lifetime:
lifetime = "frame"is recycled automatically. - Validate on change: the hot path stays minimal.
Documentation Vulfram Core