Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
29 changes: 15 additions & 14 deletions .agents/skills/add-render-pass/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
---
name: add-render-pass
description: Add a new render or compute pass to the FrameGraph end to end — the .sig PassNode and PSO declaration, code generation, the setup/render implementation, the HLSL shader, and pipeline registration. Use this skill whenever adding a new rendering effect, post-process, compute dispatch, shadow, or GBuffer stage, whenever a new PassNode or ComputePSO/GraphicsPSO is needed, or when an existing pass needs new resource reads/writes wired through the FrameGraph. Also use it when a newly added pass never executes, since that is usually a pipeline registration or setup-return problem rather than a bug in the render body.
description: Add a new render or compute pass to the FrameGraph end to end — the .prism PassNode and PSO declaration, code generation, the setup/render implementation, the HLSL shader, and pipeline registration. Use this skill whenever adding a new rendering effect, post-process, compute dispatch, shadow, or GBuffer stage, whenever a new PassNode or ComputePSO/GraphicsPSO is needed, or when an existing pass needs new resource reads/writes wired through the FrameGraph. Also use it when a newly added pass never executes, since that is usually a pipeline registration or setup-return problem rather than a bug in the render body.
---

# Adding a FrameGraph pass

A pass is declared in a `.sig` file and implemented in C++, with the generator
A pass is declared in a `.prism` file and implemented in C++, with the generator
producing the glue between them. Getting the declaration right matters more
than the render body — the declaration is what the FrameGraph uses to schedule
the pass and to compute its barriers, so a wrong read/write flag produces
validation errors or corrupt results that look like shader bugs.

Read `sources/RenderSystem/Effects/Sky.cpp` alongside `sources/SIGParser/sigs/sky.sig`
Read `sources/RenderSystem/Effects/Sky.cpp` alongside `sources/Prism/defs/sky.prism`
before starting. Between them they show both wiring styles, a graphics PSO and
several compute PSOs, resource creation, and per-mip view handling — it is the
best single reference in the tree.

## 1. Declare in a `.sig` file
## 1. Declare in a `.prism` file

Put the declaration in an existing `.sig` that matches the subsystem, or a new
one in `sources/SIGParser/sigs/`.
Put the declaration in an existing `.prism` that matches the subsystem, or a new
one in `sources/Prism/defs/`.

**Binding struct** — the shader-visible parameters. `[Bind = DefaultLayout::InstanceN]`
selects the root-signature slot; distinct structs bound in the same pass need
Expand All @@ -35,7 +35,8 @@ struct MyEffectData
}
```

**PSO** — `compute = <name>` refers to `workdir/shaders/<name>.hlsl`, and
**PSO** — `compute = "<dir>/<name>.hlsl"` is a quoted path relative to
`workdir/shaders`, extension included (the generator rejects a missing file), and
`[EntryPoint = X]` selects the function within it. One shader file can back
several PSOs through different entry points:

Expand All @@ -45,7 +46,7 @@ ComputePSO MyEffectCompute
root = DefaultLayout;

[EntryPoint = CS]
compute = my_effect;
compute = "my_effect.hlsl";
}
```

Expand Down Expand Up @@ -74,15 +75,15 @@ resource; introducing a new spelling silently creates an unrelated resource.
`PassDefault<Passes::X>` specialization declaring `setup` and `render`, which
you then define out-of-line. Without `[Static]` no such specialization exists
and the pass must be wired at runtime by assigning `setup_func`/`render_func`.
See `sources/SIGParser/templates/cpp/pass_defaults.jinja` for the exact rule.
See `sources/Prism/templates/cpp/pass_defaults.jinja` for the exact rule.

Choose `[Static]` when the pass is self-contained. Choose runtime wiring when
the pass needs state owned by a C++ object — loaded textures, cached history
buffers, persistent settings.

## 2. Regenerate

Use the `sig-regen` skill. In short: run the generator from `sources/SIGParser`,
Use the `prism-regen` skill. In short: run the generator from `sources/Prism`,
then run `generate_project.bat` because a new `PassNode` and PSO create new
files that the projects don't yet list.

Expand Down Expand Up @@ -148,9 +149,9 @@ no D3D12 output at all. In that pass, use the owning `HAL::Texture` directly.

## 4. Write the shader

Create `workdir/shaders/<name>.hlsl` matching the PSO's `compute =`/`vertex =`/
`pixel =` value, with a function named by `[EntryPoint = ...]`. Include the
generated binding header so the struct layout stays in sync with the `.sig`.
Create the file the PSO's `compute =`/`vertex =`/`pixel =` string names under
`workdir/shaders/`, with a function named by `[EntryPoint = ...]`. Include the
generated binding header so the struct layout stays in sync with the `.prism`.

## 5. Register in a pipeline

Expand All @@ -169,7 +170,7 @@ Pipeline AssetPipeline
```

Add it to every pipeline that should run it — `AssetPipeline` and the pipeline
in `test.sig` are separate graphs and adding to one does not affect the other.
in `test.prism` are separate graphs and adding to one does not affect the other.
Then regenerate again, since the pipeline block changed.

## 6. Verify
Expand Down
82 changes: 82 additions & 0 deletions .agents/skills/prism-regen/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
---
name: prism-regen
description: Regenerate C++ and HLSL code after editing any .prism file in sources/Prism/defs/. Use this skill whenever you add, edit, or remove a struct, ComputePSO, GraphicsPSO, PassNode, Pipeline entry or HLSL function in a .prism file, or whenever generated code under sources/HAL/autogen, sources/RenderSystem/FrameGraph/autogen, or workdir/shaders/autogen looks stale or out of sync with the .prism sources. Also use it when a build fails with unknown Slots::, PSOS::, or Passes:: identifiers, since that almost always means the .prism edit was never regenerated.
---

# Regenerating Prism code

`.prism` files are the single source of truth for GPU/CPU shared structs, PSO
definitions, and FrameGraph pass declarations. Editing one changes nothing on
its own — the generated C++ and HLSL must be rebuilt from it.

## The one thing that goes wrong

`generate_prism_parser.bat` does **not** regenerate code from `.prism` files. It
runs ANTLR over `Prism.g4` to rebuild the *parser*, which is only needed when
the grammar itself changes. Running it after a `.prism` edit appears to succeed
and produces no useful change — which is exactly why it's the trap.

The actual generator is `prismc.exe`, built by the `Prism` project.

## Running the generator

In Visual Studio with the Prism extension installed: **Tools → Regenerate Prism
code** (also on the Prism toolbar). It saves open `.prism` files, runs the
generator, and reports added/removed/modified files in the Output window's
"Prism" pane — including whether `generate_project.bat` is needed.

From a shell, the working directory matters: the generator reads `defs/` and
writes to `../../sources/...` and `../../workdir/...` relative to it.

```bash
cd sources/Prism && ../../bin/profile/prismc.exe
```

A `.prism` mistake makes the generator print `file(line,col): error: ...`, exit
with code 1 and write **nothing**; fix the reported lines and rerun.

Prebuilt exes in different `bin/` configurations drift independently. If the
generator or templates changed since `bin/profile/prismc.exe` was built, rebuild
the `Prism` project (Profile) first — otherwise the output won't reflect those
changes.

## Deciding whether the project needs regenerating too

Sharpmake enumerates source files at generation time, so the `.vcxproj` files
list generated sources explicitly. Modifying the *contents* of an existing
generated file is invisible to the build system, but a **new** generated file
will not compile until the projects know about it.

After running the generator, check whether the file set changed:

```bash
git status --short sources/HAL/autogen sources/RenderSystem/FrameGraph/autogen workdir/shaders/autogen
```

Lines starting with `??` (untracked) or `D` (deleted) mean the file set changed
— run `generate_project.bat`. Only `M` lines means contents changed in place and
the existing projects already cover it.

Adding a new `struct`, `ComputePSO`/`GraphicsPSO`, or `PassNode` usually creates
new files, so a new declaration generally does need the project regenerated.

## Full sequence

1. Edit the `.prism` file under `sources/Prism/defs/`.
2. Regenerate (Tools → Regenerate Prism code, or `cd sources/Prism && ../../bin/profile/prismc.exe`).
3. `git status --short` the three autogen directories.
4. If any file was added or removed, run `generate_project.bat` from the repo root.
5. Build, and confirm the new `Slots::`/`PSOS::`/`Passes::` names resolve.

## Reporting back

Say which `.prism` files changed, what the generator wrote, and — explicitly —
whether `generate_project.bat` was needed. That last point is what the next
person (or the next session) needs in order to trust the result, since a
missing project regeneration produces a confusing "identifier not found" error
far away from its cause.

Never hand-edit files under the autogen directories. They carry a
DO-NOT-EDIT banner and the next generator run silently discards the changes.
If generated output is wrong, fix the `.prism` file or the Jinja template in
`sources/Prism/templates/`.
76 changes: 0 additions & 76 deletions .agents/skills/sig-regen/SKILL.md

This file was deleted.

29 changes: 15 additions & 14 deletions .claude/skills/add-render-pass/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
---
name: add-render-pass
description: Add a new render or compute pass to the FrameGraph end to end — the .sig PassNode and PSO declaration, code generation, the setup/render implementation, the HLSL shader, and pipeline registration. Use this skill whenever adding a new rendering effect, post-process, compute dispatch, shadow, or GBuffer stage, whenever a new PassNode or ComputePSO/GraphicsPSO is needed, or when an existing pass needs new resource reads/writes wired through the FrameGraph. Also use it when a newly added pass never executes, since that is usually a pipeline registration or setup-return problem rather than a bug in the render body.
description: Add a new render or compute pass to the FrameGraph end to end — the .prism PassNode and PSO declaration, code generation, the setup/render implementation, the HLSL shader, and pipeline registration. Use this skill whenever adding a new rendering effect, post-process, compute dispatch, shadow, or GBuffer stage, whenever a new PassNode or ComputePSO/GraphicsPSO is needed, or when an existing pass needs new resource reads/writes wired through the FrameGraph. Also use it when a newly added pass never executes, since that is usually a pipeline registration or setup-return problem rather than a bug in the render body.
---

# Adding a FrameGraph pass

A pass is declared in a `.sig` file and implemented in C++, with the generator
A pass is declared in a `.prism` file and implemented in C++, with the generator
producing the glue between them. Getting the declaration right matters more
than the render body — the declaration is what the FrameGraph uses to schedule
the pass and to compute its barriers, so a wrong read/write flag produces
validation errors or corrupt results that look like shader bugs.

Read `sources/RenderSystem/Effects/Sky.cpp` alongside `sources/SIGParser/sigs/sky.sig`
Read `sources/RenderSystem/Effects/Sky.cpp` alongside `sources/Prism/defs/sky.prism`
before starting. Between them they show both wiring styles, a graphics PSO and
several compute PSOs, resource creation, and per-mip view handling — it is the
best single reference in the tree.

## 1. Declare in a `.sig` file
## 1. Declare in a `.prism` file

Put the declaration in an existing `.sig` that matches the subsystem, or a new
one in `sources/SIGParser/sigs/`.
Put the declaration in an existing `.prism` that matches the subsystem, or a new
one in `sources/Prism/defs/`.

**Binding struct** — the shader-visible parameters. `[Bind = DefaultLayout::InstanceN]`
selects the root-signature slot; distinct structs bound in the same pass need
Expand All @@ -35,7 +35,8 @@ struct MyEffectData
}
```

**PSO** — `compute = <name>` refers to `workdir/shaders/<name>.hlsl`, and
**PSO** — `compute = "<dir>/<name>.hlsl"` is a quoted path relative to
`workdir/shaders`, extension included (the generator rejects a missing file), and
`[EntryPoint = X]` selects the function within it. One shader file can back
several PSOs through different entry points:

Expand All @@ -45,7 +46,7 @@ ComputePSO MyEffectCompute
root = DefaultLayout;

[EntryPoint = CS]
compute = my_effect;
compute = "my_effect.hlsl";
}
```

Expand Down Expand Up @@ -74,15 +75,15 @@ resource; introducing a new spelling silently creates an unrelated resource.
`PassDefault<Passes::X>` specialization declaring `setup` and `render`, which
you then define out-of-line. Without `[Static]` no such specialization exists
and the pass must be wired at runtime by assigning `setup_func`/`render_func`.
See `sources/SIGParser/templates/cpp/pass_defaults.jinja` for the exact rule.
See `sources/Prism/templates/cpp/pass_defaults.jinja` for the exact rule.

Choose `[Static]` when the pass is self-contained. Choose runtime wiring when
the pass needs state owned by a C++ object — loaded textures, cached history
buffers, persistent settings.

## 2. Regenerate

Use the `sig-regen` skill. In short: run the generator from `sources/SIGParser`,
Use the `prism-regen` skill. In short: run the generator from `sources/Prism`,
then run `generate_project.bat` because a new `PassNode` and PSO create new
files that the projects don't yet list.

Expand Down Expand Up @@ -148,9 +149,9 @@ no D3D12 output at all. In that pass, use the owning `HAL::Texture` directly.

## 4. Write the shader

Create `workdir/shaders/<name>.hlsl` matching the PSO's `compute =`/`vertex =`/
`pixel =` value, with a function named by `[EntryPoint = ...]`. Include the
generated binding header so the struct layout stays in sync with the `.sig`.
Create the file the PSO's `compute =`/`vertex =`/`pixel =` string names under
`workdir/shaders/`, with a function named by `[EntryPoint = ...]`. Include the
generated binding header so the struct layout stays in sync with the `.prism`.

## 5. Register in a pipeline

Expand All @@ -169,7 +170,7 @@ Pipeline AssetPipeline
```

Add it to every pipeline that should run it — `AssetPipeline` and the pipeline
in `test.sig` are separate graphs and adding to one does not affect the other.
in `test.prism` are separate graphs and adding to one does not affect the other.
Then regenerate again, since the pipeline block changed.

## 6. Verify
Expand Down
Loading
Loading