feat(render): implement Campaign AR and terrain fidelity
This commit is contained in:
parent
99cf26e00c
commit
7a5f96ede5
368 changed files with 50611 additions and 950 deletions
227
docs/render-packs/README.md
Normal file
227
docs/render-packs/README.md
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
# Render-pack SDK v1
|
||||
|
||||
**Campaign:** Atmospheric Rendering / Shader Packs
|
||||
**Phase id:** **Campaign AR**
|
||||
**Contract version:** `RenderPackApi.Current == 1`
|
||||
|
||||
Render packs are opt-in, declarative graphics extensions. acdream's current
|
||||
retail-faithful renderer is always installed, remains the default and
|
||||
authoritative comparison path, and is restored as one complete transaction
|
||||
when a selected pack cannot run. A
|
||||
pack cannot access Vulkan, renderer internals, gameplay state, world streaming,
|
||||
or physics.
|
||||
|
||||
The public dependency is only
|
||||
`AcDream.Plugin.Abstractions`. Do not reference `AcDream.App`, Silk.NET, or a
|
||||
Vulkan binding. Three buildable external samples cover the API:
|
||||
|
||||
- [`AcDream.RenderPacks.NoOp`](../../samples/AcDream.RenderPacks.NoOp/) is the
|
||||
smallest discovery and activation conformance pack.
|
||||
- [`AcDream.RenderPacks.AtmosphericTier2`](../../samples/AcDream.RenderPacks.AtmosphericTier2/)
|
||||
declares the complete semantic atmospheric executor with deliberately
|
||||
renamed pack-owned IDs, embeds all referenced SPIR-V, and demonstrates
|
||||
moving authored sun-and-moon shadows for terrain, trees, buildings, players, and monsters.
|
||||
- [`AcDream.RenderPacks.ShadowsOnlyTier2`](../../samples/AcDream.RenderPacks.ShadowsOnlyTier2/)
|
||||
demonstrates that Tier 2 is composable: it requests the same selected-celestial
|
||||
caster/receiver semantics without Tier-1 post-processing or volumetric
|
||||
shafts.
|
||||
|
||||
## Quick start
|
||||
|
||||
1. Target `.NET 10` and reference `AcDream.Plugin.Abstractions` with runtime
|
||||
copy disabled. The acdream host supplies that assembly.
|
||||
2. Add [`plugin.json`](plugin-manifest-v1.schema.json), include
|
||||
`"kinds": ["renderPack"]`, and copy it beside the built entry DLL.
|
||||
3. Expose exactly one public, parameterless `IRenderPackPlugin` entry point.
|
||||
4. Construct immutable `RenderPackDescriptor` values and register them from
|
||||
`Register`. Registration must only publish declarations; do not open assets,
|
||||
compile shaders, start threads, or allocate native/GPU resources.
|
||||
5. Supply shader bytes lazily through `IRenderPackAssets.OpenRead`. Asset keys
|
||||
are forward-slash relative logical paths: never rooted, backslash-based, or
|
||||
`.`/`..` traversals.
|
||||
6. Build and run the SDK validator:
|
||||
|
||||
```powershell
|
||||
dotnet build samples/AcDream.RenderPacks.NoOp/AcDream.RenderPacks.NoOp.csproj -c Release
|
||||
dotnet run --project tools/RenderPackValidator/AcDream.Tools.RenderPackValidator.csproj -c Release -- samples/AcDream.RenderPacks.NoOp/bin/Release/net10.0
|
||||
```
|
||||
|
||||
Substitute `AcDream.RenderPacks.AtmosphericTier2` in both paths to validate
|
||||
the complete Tier 2/Tier 2+ example and its embedded shader interfaces.
|
||||
|
||||
The validator executes the managed registration entry point. Use it only on a
|
||||
pack you trust. It loads no App, RHI, or Vulkan assembly and creates no GPU
|
||||
objects. It validates the manifest, v1 declarations, referenced asset keys,
|
||||
SPIR-V stage/entry point and complete v1 binary interface, managed
|
||||
registration, and duplicate pack IDs. Hardware and driver compatibility remain
|
||||
client-side activation checks.
|
||||
|
||||
To launch a visible offline preview of acdream with the built-in Atmospheric
|
||||
pack and a disposable settings profile:
|
||||
|
||||
```powershell
|
||||
.\tools\launch-atmospheric-preview.ps1 -Preset High
|
||||
```
|
||||
|
||||
The preview starts `AcDream.App` with audio disabled, clears inherited
|
||||
`ACDREAM_*` live/automation/diagnostic state for that child, and leaves the
|
||||
user's normal acdream settings untouched. It records the binary identity,
|
||||
selected audio mode, and separate stdout/stderr logs beside the disposable
|
||||
profile. To exercise OpenAL explicitly, add `-EnableAudio`.
|
||||
|
||||
Vertex and fragment asset keys are independent opaque keys; they do not need
|
||||
matching basenames or a host shader-directory stem. On explicit selection the
|
||||
client opens each declared stream, validates it, copies the bytes into the
|
||||
isolated candidate, and creates shader modules from those immutable blobs.
|
||||
The pipeline retains neither the stream nor a path into the plugin directory.
|
||||
Each stage must be little-endian, word-aligned SPIR-V no larger than 16 MiB.
|
||||
|
||||
Shader-visible pack settings are deliberately capped at 64 declarations. The
|
||||
public `PackSettings` binding and value encoding are documented in the
|
||||
[`semantic binding table`](semantic-bindings-v1.md#packsettings-set-3-binding-8-256-bytes).
|
||||
A persisted user override wins the selected preset override, which wins the
|
||||
declaration default. Overrides are stored by stable pack ID plus setting ID;
|
||||
the host validates the selected descriptor's kind, invariant numeric grammar,
|
||||
range, step, and choice list before supplying the resolved scalars. No renderer
|
||||
object is exposed to managed code.
|
||||
|
||||
When a pack is selected, the retained Config page appends its declared
|
||||
Boolean, bounded Float/Integer, and Choice controls under **Graphics
|
||||
Enhancements**. Changing packs replaces only that optional tail; retail's 39
|
||||
authored Config rows remain unchanged. Numeric controls snap to declared bounds
|
||||
and steps, preset changes retain explicit user overrides, and a pack change
|
||||
starts with an empty valid override map for the new stable pack identity.
|
||||
|
||||
## Manifest
|
||||
|
||||
The authoritative machine-readable schema is
|
||||
[`plugin-manifest-v1.schema.json`](plugin-manifest-v1.schema.json).
|
||||
|
||||
| Field | Meaning |
|
||||
|---|---|
|
||||
| `id` | Stable lowercase logical plugin ID. It is persisted and must not be localized or reused. |
|
||||
| `displayName` | User-visible plugin name. |
|
||||
| `version` | Dotted `System.Version`-compatible package version. |
|
||||
| `entryDll` | Safe path beneath the plugin directory to the managed entry DLL. |
|
||||
| `apiVersion` | General `PluginApi` version. v1 is `1`; this is distinct from `RenderPackApi`. |
|
||||
| `dependencies` | Optional plugin IDs that must load first. |
|
||||
| `kinds` | Entry-point kinds. Include `renderPack`; omission means legacy `gameplay` only. A hybrid lists both. |
|
||||
|
||||
Install one plugin directory containing this manifest, the entry DLL, its
|
||||
private managed dependencies, and declared shader assets. Do not redistribute
|
||||
`AcDream.Plugin.Abstractions.dll` in that directory: type identity is shared
|
||||
from the host.
|
||||
|
||||
## Declaration schema
|
||||
|
||||
The C# records in `AcDream.Plugin.Abstractions.Rendering` are the public v1
|
||||
declaration schema. `RenderPackShaderAbi` publishes the corresponding numeric
|
||||
SPIR-V set, binding, block-size, and capacity constants. They are intentionally
|
||||
BCL-only and expose no Vulkan handle.
|
||||
|
||||
| Declaration | What the pack supplies | What the host owns |
|
||||
|---|---|---|
|
||||
| `RenderPackDescriptor` | Identity/version, highest tier, capabilities, resources, passes, replays, variants, presets, settings, atmosphere policy | Validation, candidate creation, activation and fallback |
|
||||
| `RenderResourceDeclaration` | Logical ID, portable format, extent, usage, lifetime, estimated bytes | Images/buffers, allocation, barriers, frame-flight retirement |
|
||||
| `RenderPassDeclaration` | Fixed hook, shader asset keys, semantic inputs, logical resource reads/writes | Render graph order, descriptor layout, pipeline, command recording |
|
||||
| `SceneReplayDeclaration` | One supported replay semantic, caster flags, 1–4 views | Resident caster selection and existing batched submissions |
|
||||
| `PipelineVariantDeclaration` | Base pipeline semantic, shader assets, compatible material flags, inputs | Visibility, mesh/material ownership, fixed renderer state |
|
||||
| `RenderQualityPreset` | Capability requirements, resource/setting overrides, optional execution hints, and p50/p99 CPU/GPU/VRAM ceilings | Availability, explicit selection and stable-boundary swaps |
|
||||
| `RenderSettingDeclaration` | Stable ID, kind, default, bounds/choices | Persistence and conditional Display UI |
|
||||
| `AtmospherePolicyDeclaration` | Ordered sun and selected-light elevation curves plus explicit `activeDayGroup` multipliers | Authored Dereth clock, celestial source, day group, weather and indoor state |
|
||||
|
||||
IDs use `^[a-z][a-z0-9._-]*$`, are case-insensitively unique within each
|
||||
declaration kind, and remain stable across updates. A pack must declare at
|
||||
least one quality preset and at most 64 settings. The SDK ceiling is 256 MiB pack-owned resident GPU
|
||||
memory, 16 MiB per SPIR-V asset, 16,384 pixels per absolute image dimension,
|
||||
256 image layers, and four scene-replay views. A physical device may expose a
|
||||
lower ceiling or reject a preset whose mandatory capabilities are absent.
|
||||
For API v1 the host admits optional pack memory from one eighth of the selected
|
||||
adapter's probed device-local heaps, capped at 256 MiB resident and 512 MiB
|
||||
transient multisample storage. Presets remain listed with exact limit reasons.
|
||||
Auto requires asynchronous timestamps and uses Low when Medium cannot fit. At
|
||||
runtime, Auto alone watches the selected preset's declared inclusive-GPU p99,
|
||||
pack-added CPU p99, and resident-GPU budgets. If Low remains over any of those
|
||||
budgets for 180 stable samples, the whole pack fails safely to acdream's
|
||||
default renderer with the measured and declared limits in the failure reason.
|
||||
Explicit Low remains selectable and is not silently disabled by the Auto
|
||||
performance policy.
|
||||
|
||||
A Tier-2 directional-shadow elevation curve must resolve to exactly zero at
|
||||
and below the authored 0-degree horizon. Every declared non-positive point
|
||||
must therefore have multiplier `0`; if the curve omits an exact 0-degree
|
||||
point, its first positive point must also be `0` so endpoint clamping or
|
||||
interpolation cannot manufacture a below-horizon directional shadow. The host still
|
||||
owns the independent no-selected-light-energy and indoor gates.
|
||||
|
||||
The built-in Atmospheric Low preset preserves the complete directional-shadow
|
||||
caster set (terrain, opaque and alpha-cutout world geometry, and both animated
|
||||
classes). It reduces cost with two 768 x 768 shadow maps and the ordinary
|
||||
six-pass, quarter-resolution separable post chain: sun occlusion, sun rays,
|
||||
bloom downsample, horizontal blur, vertical blur, and filmic composition. It
|
||||
does not remove a caster class or use the fused post-process hint.
|
||||
|
||||
`FusedAtmosphericPostProcess` is an optional external-pack Low-preset execution
|
||||
hint for the standard atmospheric graph; it is not built-in Low behavior. An
|
||||
opting-in shader pack implements the PackPass ABI below: the host feeds scene
|
||||
depth directly to sun rays and asks filmic to evaluate the declared bloom
|
||||
extraction and separable filter while composing the final image. This reduces
|
||||
command recording without disabling rays, bloom, or filmic composition. The
|
||||
host never infers the hint from pack identity; unknown hints, non-Low use, and
|
||||
incomplete standard graphs fail validation.
|
||||
|
||||
`MultiviewDirectionalShadowCascades` is a separate explicit Low-preset
|
||||
execution hint. The opting-in pack must implement three multiview caster
|
||||
variants. The host records one layered directional-depth
|
||||
pass with view mask `0b11`; `gl_ViewIndex` selects the exact two declared Low
|
||||
cascade matrices. Terrain, opaque, and alpha-cutout commands retain their
|
||||
ordinary pipeline, transform, cull, and cutout semantics. The preset must require
|
||||
`MultiviewDirectionalShadowCascades`; unsupported hardware makes that Low preset
|
||||
unavailable before allocation. A zero hint retains ordinary per-cascade passes.
|
||||
|
||||
Resources are declared in execution order: a pass cannot read a pack resource
|
||||
before an earlier pass writes it, and one pass cannot read and write the same
|
||||
resource. `WorldColor`, `SceneDepth`, and other renderer semantics are not pack
|
||||
resources and are named in `SemanticInputs` instead. API v1 exposes four
|
||||
sampled pass-input slots; buffers, `StructuredData`, and storage resources are
|
||||
reserved enum values and are rejected until a public binding contract exists.
|
||||
Colour image arrays are likewise reserved; v1 arrays are directional-depth
|
||||
maps. One declared pass writes at most one attachment. Only `ToneMap` and
|
||||
`AfterToneMapBeforePrivateViewports` may write directly to the host surface
|
||||
without naming a pack resource.
|
||||
|
||||
Every semantic input implies its capability and the descriptor must list that
|
||||
capability as required: world colour, scene depth/normals, authored sun/selected-
|
||||
celestial/day/weather facts, animation transforms, and directional maps cannot
|
||||
be treated as
|
||||
optional after a pass unconditionally declares them.
|
||||
|
||||
## Lifecycle and versioning
|
||||
|
||||
- Discovery calls `Register` but does not open assets or allocate GPU objects.
|
||||
- Installing a pack never selects it. The user selects a pack ID, version, and
|
||||
preset; `acdream default (retail-faithful)` is always available.
|
||||
- The client validates every declaration and selected asset, builds the full
|
||||
candidate beside the active retail graph, then swaps at a frame boundary.
|
||||
- Dispose the registration handle to withdraw the descriptor. The host also
|
||||
withdraws every handle before unloading its collectible plugin context.
|
||||
- `PluginApi` versions the general managed plugin ABI. `RenderPackApi` versions
|
||||
these graphics declarations. Additive enum/record support stays compatible;
|
||||
a breaking contract requires a new render-pack API version and explicit
|
||||
compatibility path.
|
||||
- Persisted identity is pack ID + pack version + preset ID, never list index.
|
||||
User-authored setting strings are keyed by the same stable pack identity and
|
||||
stable setting ID, never declaration or menu index.
|
||||
|
||||
"Device recreation" in the v1 SDK means full teardown of the old renderer,
|
||||
graphics context, and device, followed by construction and capability probing
|
||||
of a fresh context/device. Retail is authoritative until a fresh pack candidate
|
||||
validates and activates. The SDK does not promise live recovery of a pack or
|
||||
renderer after `VK_ERROR_DEVICE_LOST`; that error is terminal to the old device
|
||||
lifetime.
|
||||
|
||||
The complete campaign contract, budgets, and non-goals remain in
|
||||
[`2026-08-21-atmospheric-rendering.md`](../plans/2026-08-21-atmospheric-rendering.md).
|
||||
The public shader-facing contracts are the
|
||||
[`semantic binding table`](semantic-bindings-v1.md) and
|
||||
[`compatibility/failure guide`](compatibility-and-failure-v1.md).
|
||||
134
docs/render-packs/compatibility-and-failure-v1.md
Normal file
134
docs/render-packs/compatibility-and-failure-v1.md
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
# Render-pack compatibility and failure handling v1
|
||||
|
||||
**Campaign phase id:** **TBD**
|
||||
|
||||
Compatibility is a declaration and activation result, not a promise inferred
|
||||
from a GPU brand. The client keeps unsupported packs visible with one exact
|
||||
reason, refuses to select an unavailable preset, and continues rendering the
|
||||
authoritative acdream default (retail-faithful) path.
|
||||
|
||||
## Author responsibilities
|
||||
|
||||
- Declare every mandatory facility in `RequiredCapabilities`. Use
|
||||
`OptionalCapabilities` only when the pack has a deterministic path that does
|
||||
not need it.
|
||||
- Gate each preset independently. Low must remain semantically correct; lower
|
||||
shadow resolution or reach rather than silently removing trees, monsters,
|
||||
players, buildings, alpha cutouts, or animated transforms.
|
||||
- Keep resource estimates conservative and below the preset and 256 MiB SDK
|
||||
ceilings. The host clamps dimensions and bytes before allocation. Its
|
||||
optional-pack memory policy admits at most one eighth of the selected
|
||||
adapter's probed device-local heap, capped at 256 MiB resident and 512 MiB
|
||||
transient multisample storage; the lower value wins and is printed in an
|
||||
unavailable-preset reason.
|
||||
- Use only declared hooks, semantic inputs, resources, scene replays and base
|
||||
pipeline variants. Pack code receives no arbitrary per-frame callback,
|
||||
command buffer, gameplay owner, RHI object, or Vulkan handle.
|
||||
- Treat registration as pure declaration publication. `OpenRead` must return a
|
||||
new readable stream for the exact requested key and must not retain a world
|
||||
generation or borrowed frame state.
|
||||
- Ship SPIR-V words little-endian, four-byte aligned, no larger than 16 MiB per
|
||||
asset, and compatible with the published v1 semantic binding ABI. Both the
|
||||
SDK and client validate the binary stage, `main` entry point, descriptor
|
||||
allowlist, exact uniform/push layouts, and read-only storage contract before
|
||||
pipeline creation. Vertex and fragment keys are independent logical keys;
|
||||
the selected candidate copies their blobs and never resolves them through
|
||||
the host shader directory.
|
||||
- Declare no more than 64 settings and keep their descriptor order stable. The
|
||||
set-3/binding-8 shader mapping is positional: a persisted user override wins
|
||||
the selected-preset override, which wins the declaration default. Boolean
|
||||
becomes 0/1, Choice becomes its zero-based choice index, numeric strings use
|
||||
invariant culture, and unused or defensively invalid slots are zero. The
|
||||
selected descriptor validates every user string against kind, range, step,
|
||||
and choices before activation.
|
||||
|
||||
## Client transaction
|
||||
|
||||
1. Discover the manifest and descriptor without opening assets or constructing
|
||||
GPU objects.
|
||||
2. Compare required capabilities and preset ceilings with the active physical
|
||||
device's probed `maxImageDimension2D`, `maxImageArrayLayers`, device-local
|
||||
heap bytes, and format/timestamp support. An unsupported pack remains
|
||||
installed and its individual presets remain visible with exact
|
||||
needed-versus-provided reasons.
|
||||
3. After explicit selection, validate every referenced asset and shader
|
||||
interface, then build every resource and pipeline in an isolated candidate.
|
||||
4. Activate the complete candidate at a stable frame boundary. Until that
|
||||
point retail keeps rendering.
|
||||
5. If any step fails, retire the candidate through normal GPU-flight fences,
|
||||
record one stable diagnostic, select `acdream default`, and do not retry
|
||||
that pack again during the session.
|
||||
|
||||
No half-enabled graph is valid. A missing bloom shader does not leave shadows
|
||||
active; a failed shadow pipeline does not leave a world-colour intermediate or
|
||||
stale descriptor alive.
|
||||
|
||||
Auto is a logical selector rather than an allocated preset. It requires
|
||||
asynchronous GPU timestamps, starts at Medium when Medium fits, otherwise
|
||||
starts and stays at Low, and never promotes beyond the highest contiguous
|
||||
compatible preset. If Low itself cannot fit, Auto fails safely to Retail and
|
||||
reports the Low limit that failed.
|
||||
|
||||
Runtime Auto decisions use the active preset's declared inclusive-GPU p99,
|
||||
pack-added CPU p99, and resident-GPU budgets. An over-budget Medium selection
|
||||
can step down to Low; if Low then remains over any declared limit for 180
|
||||
stable samples, the host atomically deactivates the complete pack, reports the
|
||||
measured and budget values, and enters `FailedToRetail` without a retry loop.
|
||||
This performance fallback is Auto-only. Explicit Low remains selectable when
|
||||
only timestamp support is missing and is never silently reduced by removing
|
||||
terrain, trees, buildings, monsters, players, alpha cutouts, or animated
|
||||
casters. The built-in Low preset instead uses two 768 x 768 shadow maps and an
|
||||
unfused six-pass, quarter-resolution separable post chain. An ordinary explicit
|
||||
Low validation, candidate-build, or runtime failure still follows the complete
|
||||
transactional fallback rules above.
|
||||
|
||||
## Diagnostic categories
|
||||
|
||||
| Category | Example user-facing reason | Recovery |
|
||||
|---|---|---|
|
||||
| Manifest | `plugin.json does not declare the renderPack kind` | Correct/reinstall the package |
|
||||
| Managed ABI | `apiVersion 2 is unsupported; this SDK supports 1..1` | Use a compatible client or rebuild the pack |
|
||||
| Pack ABI | `requires render-pack API 2; this client supports 1..1` | Same as above |
|
||||
| Capability | `requires unsupported capability DirectionalShadowMaps` | Select a supported preset/device or retail |
|
||||
| Declaration | `Pass 'blur' reads resource 'bloom-a' before it is written` | Correct the descriptor |
|
||||
| User setting | `user override 'exposure' has invalid Float value '1,5'` | Correct/remove that stable setting-ID override; retail remains active |
|
||||
| Asset | `asset 'bloom.frag.spv' is not valid SPIR-V` | Rebuild/reinstall the pack |
|
||||
| Shader interface | `AtmosphericFrame block does not match v1` | Recompile against the v1 binding table |
|
||||
| Resource ceiling | `preset 'high' exceeds the pack memory ceiling` | Reduce the preset declaration |
|
||||
| Auto performance | `Low remained over its declared performance budget for 180 stable samples` | Complete pack falls back to Retail; select explicit Low only after reviewing the measured limits |
|
||||
| Candidate build | `pipeline creation failed for 'directional-shadow-world-cutout'` | Driver/asset diagnosis; retail for this session |
|
||||
| Runtime/device | `selected pack failed validation on the fresh device` | Retail on the fresh renderer for this session; no retry loop |
|
||||
| Removal/update | `selected pack is no longer installed` | Retail, while retaining the notice |
|
||||
|
||||
Diagnostics and screenshot metadata record pack ID, pack version, preset ID,
|
||||
compatibility result and fallback reason. Enhanced screenshots are not retail
|
||||
parity evidence.
|
||||
|
||||
## Update and removal
|
||||
|
||||
Pack IDs remain stable across compatible updates; increment `PackVersion` and
|
||||
manifest `version` together. A preset or setting ID that persists must keep its
|
||||
meaning. User values are persisted as invariant strings under the selected
|
||||
pack ID and setting ID, so declaration reordering cannot retarget a value. If
|
||||
an update removes or changes a persisted setting incompatibly, selection fails
|
||||
atomically to retail with the unknown/invalid override reason instead of
|
||||
silently applying it elsewhere. If an update removes the selected preset, the client falls back to a
|
||||
compatible declared preset only after explicit policy permits it; otherwise it
|
||||
selects retail. Removing or unloading a pack first withdraws registrations,
|
||||
then retires GPU-flight resources, then releases the collectible load context.
|
||||
|
||||
The built-in atmospheric pack's `sun-shadow-*` setting IDs predate the
|
||||
selected-celestial source contract. They remain stable persisted identifiers;
|
||||
their current labels and semantics apply to directional shadows from whichever
|
||||
authored celestial source the renderer selects.
|
||||
|
||||
Reconnect, portal travel, resize and world-generation replacement do not
|
||||
re-register managed packs. Renderer-owned resources are recreated or retired
|
||||
within the same generation/fence rules; pack assets never own gameplay,
|
||||
streaming, collision, or physics lifetime.
|
||||
|
||||
For v1, device recreation is not an in-place `VK_ERROR_DEVICE_LOST` recovery
|
||||
path. The host tears down the complete old renderer, context, and device, then
|
||||
constructs and probes a new context/device. The default retail renderer remains
|
||||
authoritative while the selected pack is validated as a fresh candidate; a
|
||||
failed candidate stays on retail without an automatic retry loop.
|
||||
68
docs/render-packs/plugin-manifest-v1.schema.json
Normal file
68
docs/render-packs/plugin-manifest-v1.schema.json
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "urn:acdream:render-pack:plugin-manifest:v1",
|
||||
"title": "acdream plugin manifest v1",
|
||||
"description": "Manifest shared by gameplay plugins and declarative render packs. A render pack includes renderPack in kinds.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"displayName",
|
||||
"version",
|
||||
"entryDll",
|
||||
"apiVersion"
|
||||
],
|
||||
"properties": {
|
||||
"$schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 128,
|
||||
"pattern": "^[a-z][a-z0-9._-]*$",
|
||||
"description": "Stable plugin identity. It is persisted; do not reuse or localize it."
|
||||
},
|
||||
"displayName": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"pattern": "^[0-9]+(?:\\.[0-9]+){1,3}$",
|
||||
"description": "Dotted System.Version-compatible package version."
|
||||
},
|
||||
"entryDll": {
|
||||
"type": "string",
|
||||
"minLength": 5,
|
||||
"maxLength": 512,
|
||||
"pattern": "^(?![A-Za-z]:)(?!/)(?!.*(?:^|/)\\.\\.(?:/|$))[^\\\\]+\\.[dD][lL][lL]$",
|
||||
"description": "Safe forward-slash relative path to the managed entry assembly."
|
||||
},
|
||||
"apiVersion": {
|
||||
"type": "integer",
|
||||
"const": 1,
|
||||
"description": "AcDream.Plugin.Abstractions PluginApi version, not RenderPackApi."
|
||||
},
|
||||
"dependencies": {
|
||||
"type": "array",
|
||||
"uniqueItems": true,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z][a-z0-9._-]*$"
|
||||
},
|
||||
"default": []
|
||||
},
|
||||
"kinds": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"uniqueItems": true,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": ["gameplay", "renderPack"]
|
||||
},
|
||||
"default": ["gameplay"],
|
||||
"description": "Omitting kinds preserves legacy gameplay-plugin behavior. A render pack must explicitly include renderPack."
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
||||
381
docs/render-packs/semantic-bindings-v1.md
Normal file
381
docs/render-packs/semantic-bindings-v1.md
Normal file
|
|
@ -0,0 +1,381 @@
|
|||
# Render-pack shader ABI and semantic bindings v1
|
||||
|
||||
**Campaign phase id:** **Campaign AR**
|
||||
**Render-pack API:** `1`
|
||||
|
||||
This is a SPIR-V binary contract over renderer-owned descriptors. It does not
|
||||
expose Vulkan descriptor sets, descriptor handles, images, buffers, samplers,
|
||||
command buffers, devices, queues, or fences to managed pack code. A pack only
|
||||
declares semantic inputs and supplies SPIR-V; the renderer validates the
|
||||
interface and binds immutable frame data.
|
||||
|
||||
## Semantic execution and stable identity
|
||||
|
||||
`RenderResourceSemantic`, `RenderPassSemantic`,
|
||||
`RenderPipelineVariantSemantic`, `RenderQualitySemantic`, and
|
||||
`RenderSettingSemantic` select renderer-owned execution roles. Pack-owned IDs
|
||||
remain stable persistence, UI, graph-edge, and diagnostic keys; the executor
|
||||
never recognizes a role by comparing an ID or asset-name string. Custom
|
||||
fullscreen declarations retain `Custom` semantics and are executed from their
|
||||
declared hooks and edges.
|
||||
|
||||
Every non-custom semantic is unique within its declaration kind. The complete
|
||||
Tier-2+ atmospheric executor requires its exact v1 pass/resource/pipeline-
|
||||
variant roles, hook order, scene replay, and graph edges. A Tier-2 pack may
|
||||
instead declare the directional-shadow component plus the technical custom
|
||||
`WorldColor` tone-map copy needed to present the HDR world. That profile still
|
||||
requires the exact shadow depth resource/pass, five caster/receiver variants,
|
||||
headline-caster replay, capabilities, settings, and elevation policy; it does
|
||||
not require bloom, rays, grading, vignette, or volumetric shafts. Any other
|
||||
partial or malformed semantic graph fails validation even when all pack-owned
|
||||
IDs remain syntactically valid.
|
||||
|
||||
Directional-shadow declarations use
|
||||
`SelectedCelestialDirectionalLight` together with the required
|
||||
`AuthoredCelestialDirectionalLight` capability and the descriptor's
|
||||
`DirectionalShadowLightElevationResponse`. `SunDirection`,
|
||||
`SunElevationResponse`, and `VolumetricShaftSunElevationResponse` remain the
|
||||
separate sun-specific atmosphere contract for rays and shafts.
|
||||
The public v1 point record remains named `SunElevationResponsePoint` for ABI
|
||||
compatibility; points stored in `DirectionalShadowLightElevationResponse` are
|
||||
interpreted against the selected celestial light's elevation.
|
||||
|
||||
## Fixed descriptor ownership
|
||||
|
||||
| Set | Binding | Shader declaration | Owner and use |
|
||||
|---:|---:|---|---|
|
||||
| 3 | 5 | `AtmosphericFrame` std140 uniform block | Renderer-owned camera/reconstruction, authored sun/day/weather and frame facts |
|
||||
| 3 | 6 | `DirectionalShadow` std140 uniform block | Renderer-owned cascade matrices, splits, shadow texture slot, shadow policy, and selected authored celestial direction |
|
||||
| 3 | 7 | `PackPass` std140 uniform block | Renderer-resolved pass resource slots, output facts and pass-local parameters |
|
||||
| 3 | 8 | `PackSettings` std140 uniform block | Renderer-resolved declaration-order scalar values for the selected preset |
|
||||
| 2 | 0 | `sampler2DArray uTextures[]` combined-image-sampler array | Existing global sampled-texture table; index with host-supplied slot IDs and `nonuniformEXT` |
|
||||
|
||||
Set 0 remains the renderer's existing storage-buffer set. A declared base
|
||||
pipeline variant inherits the exact renderer pipeline ABI it specializes; it
|
||||
does not gain arbitrary set-0 storage access. In particular,
|
||||
`ShadowCasterTransforms` reuses the renderer's existing per-instance transform
|
||||
publication rather than publishing a second animation pose.
|
||||
|
||||
Set 1 remains the current retail uniform layout at bindings 1–4. Pack shaders
|
||||
must not redeclare or alias it. Set 3 is strictly opt-in: retail pipeline
|
||||
layouts contain only sets 0–2, and the host creates no set-3 Vulkan object
|
||||
until a validated pack pipeline is activated. Bindings other than those in the
|
||||
table are reserved and validation rejects them.
|
||||
|
||||
## SPIR-V interface validation
|
||||
|
||||
Candidate activation and the standalone authoring validator inspect the
|
||||
actual SPIR-V binary before any shader module or pipeline is created. Each
|
||||
asset must expose exactly the declared vertex or fragment stage with entry
|
||||
point `main`. A fullscreen pass may declare only the sampled table at set 2,
|
||||
binding 0 when its declaration supplies a sampled semantic/resource input,
|
||||
plus the role-appropriate set-3 blocks. It may not access renderer-private set
|
||||
0 or retail set 1. A retained-scene pipeline variant may use only the base
|
||||
set-0/set-1 bindings documented for that exact semantic role, plus its allowed
|
||||
set-2/set-3 bindings.
|
||||
|
||||
Validation checks descriptor type and count, all set-3 uniform-block member
|
||||
types, offsets, strides, and total shapes, and any declared push block against
|
||||
the exact 96-byte retail layout below. Renderer storage buffers inherited by a
|
||||
variant must be read-only; storage images, arbitrary storage descriptors, and
|
||||
`OpImageWrite` are forbidden. An absent, malformed, aliased, writable, or
|
||||
undeclared interface rejects the whole candidate atomically to retail with a
|
||||
specific reason. Validation never exposes or accepts a Vulkan handle.
|
||||
|
||||
The binary member layout is validated against matching host structs. The
|
||||
checked-in shared render-pack GLSL includes are the byte-offset SSOT; authors
|
||||
include those definitions rather than maintaining a private copy. The tables
|
||||
below state the same values for review and tool diagnostics.
|
||||
|
||||
### `AtmosphericFrame` — set 3, binding 5, 160 bytes
|
||||
|
||||
```glsl
|
||||
layout(std140, set = 3, binding = 5) uniform AtmosphericFrame {
|
||||
vec4 uAtmosphereSunScreen; // @0: uv.xy, resolved ray strength, elevation degrees
|
||||
vec4 uAtmosphereSunColor; // @16: linear rgb, combined ray-policy multiplier
|
||||
vec4 uAtmosphereViewport; // @32: width, height, 1/width, 1/height
|
||||
vec4 uAtmosphereWeather; // @48: WeatherKind numeric, intensity, delta seconds, outdoor 0/1
|
||||
vec4 uAtmosphereSunDirection; // @64: surface-to-sun xyz, authored direction brightness
|
||||
vec4 uAtmospherePolicy; // @80: day group, group factor, shadow factor, shaft factor
|
||||
mat4 uAtmosphereInverseViewProjection; // @96
|
||||
};
|
||||
```
|
||||
|
||||
`uAtmosphereSunScreen.xy` uses normalized main-world viewport coordinates. The two
|
||||
strength fields are host-evaluated authored/policy facts; they do not create a
|
||||
second sky or weather owner. `uAtmosphereWeather.x` is numerically integral and must be
|
||||
interpreted with this v1 table, not guessed from colour or time:
|
||||
|
||||
| Numeric value | Weather kind |
|
||||
|---:|---|
|
||||
| 0 | Clear |
|
||||
| 1 | Overcast |
|
||||
| 2 | Rain |
|
||||
| 3 | Snow |
|
||||
| 4 | Storm |
|
||||
|
||||
All other values are reserved. `uAtmosphereWeather.y` is the transition
|
||||
intensity in the inclusive range 0–1.
|
||||
|
||||
`uAtmosphereSunDirection.xyz` is normalized and points from a lit surface
|
||||
toward the authored sun. `uAtmosphereSunScreen.z` is the resolved visible ray
|
||||
strength; `uAtmosphereSunColor.w` is the combined ray elevation/day-group/
|
||||
weather policy multiplier before a pass's own declared setting. In
|
||||
`uAtmospherePolicy`, `.x` is the numerically integral active day group, `.y` is
|
||||
that group's declared multiplier, `.z` is the declared directional-shadow
|
||||
elevation factor, and `.w` is the declared volumetric-shaft elevation factor.
|
||||
Shadow curves interpolate in sine-of-elevation space; shaft curves use
|
||||
smoothstep interpolation in elevation-degree space. These are exact values
|
||||
from the selected pack's `AtmospherePolicyDeclaration`, not built-in fallback
|
||||
curves. An accepted directional-shadow curve resolves to exactly zero at and
|
||||
below the authored 0-degree horizon; non-positive points must be zero, and a
|
||||
curve without an exact 0-degree point must make its first positive point zero.
|
||||
`uAtmosphereInverseViewProjection` reconstructs main-world positions
|
||||
from scene depth and the normalized viewport coordinates. Matrix convention
|
||||
and depth range match the shared push-block `viewProjection`.
|
||||
|
||||
### `PackPass` — set 3, binding 7, 64 bytes
|
||||
|
||||
```glsl
|
||||
layout(std140, set = 3, binding = 7) uniform PackPass {
|
||||
vec4 uPackParams0; // @0
|
||||
vec4 uPackParams1; // @16
|
||||
vec4 uPackParams2; // @32
|
||||
vec4 uPackParams3; // @48
|
||||
};
|
||||
```
|
||||
|
||||
The active semantic pass defines these sixteen scalar meanings. Unused values
|
||||
are zero. A pass cannot reinterpret values owned by a different pass. Sampled
|
||||
pass inputs use logical `textureIndexA` through `textureIndexD` in the shared push block;
|
||||
binding 7 carries scalar/vector policy and filter parameters, not descriptors.
|
||||
|
||||
The optional external-pack Low-preset `FusedAtmosphericPostProcess` execution
|
||||
hint uses these fixed values. The built-in Low preset does not declare it:
|
||||
|
||||
| Semantic pass | Values |
|
||||
|---|---|
|
||||
| `SunRays` | `uPackParams1 = (1, logicalMaskWidth, logicalMaskHeight, 0)`; input A is scene depth and the shader reconstructs the declared RGBA8 sun mask before radial integration |
|
||||
| `BloomDownsample` / both `BloomBlur` passes | Declared for the standard graph but not recorded for this preset; their threshold, knee, strength, offsets, and weights remain authoritative inputs to filmic |
|
||||
| `FilmicComposite` | `uPackParams1.z = 1`; `uPackParams2 = (bloomStrength, threshold, knee, hasVolumetric)`, `uPackParams3.xy = logicalBloomTexelStep`; inputs A/B/C are world color, sun rays, and optional volumetric shafts, and filmic evaluates the full separable bloom kernel before composition |
|
||||
|
||||
Zero flags retain the ordinary six-pass atmospheric graph. The built-in Low
|
||||
preset uses that zero-flag path; Medium, High, and external packs that do not
|
||||
opt in never use this fused ABI.
|
||||
|
||||
### Multiview directional-shadow cascades
|
||||
|
||||
The optional Low-preset `MultiviewDirectionalShadowCascades` execution
|
||||
hint requires the three `*MultiviewDirectionalShadowCaster` variants and the
|
||||
matching capability in the Low preset. The host begins one layered depth pass
|
||||
with `viewMask = 0b11`; each vertex shader indexes `uShadowWorldToClip` with
|
||||
`gl_ViewIndex`. Commands retain exact order, `BaseInstance`, the shared N.5
|
||||
world-transform arena, texture index/layer, fixed-function culling, alpha cutoff
|
||||
`0.05`, and both fitted cascade matrices. With no hint the host records the
|
||||
ordinary one-pass-per-cascade path. Unsupported hardware makes the hinted preset
|
||||
unavailable rather than silently selecting an over-budget execution form.
|
||||
|
||||
### `DirectionalShadow` — set 3, binding 6, 336 bytes
|
||||
|
||||
```glsl
|
||||
layout(std140, set = 3, binding = 6) uniform DirectionalShadow {
|
||||
mat4 uShadowWorldToClip[4]; // @0, @64, @128, @192
|
||||
vec4 uShadowSplitFarMeters; // @256
|
||||
vec4 uShadowControl; // @272
|
||||
vec4 uShadowBiasMeters; // @288
|
||||
uvec4 uShadowTextureAndFlags; // @304
|
||||
vec4 uShadowLightDirectionAndSource; // @320
|
||||
} directionalShadow;
|
||||
```
|
||||
|
||||
Field meanings are fixed:
|
||||
|
||||
| Field/component | Meaning |
|
||||
|---|---|
|
||||
| `uShadowWorldToClip[0..3]` | Texel-stabilized world-to-shadow-clip matrices; only the first `cascadeCount` entries are active |
|
||||
| `uShadowSplitFarMeters` | Far distance of cascades 0–3 in camera-eye metres |
|
||||
| `uShadowControl.x` | Directional shadow strength |
|
||||
| `uShadowControl.y` | Filter softness |
|
||||
| `uShadowControl.z` | Maximum shadow reach in metres, clamped to resident data |
|
||||
| `uShadowControl.w` | Cascade blend width in metres |
|
||||
| `uShadowBiasMeters.x` | Constant receiver/caster bias in world metres |
|
||||
| `uShadowBiasMeters.y` | Slope-scaled bias in world metres |
|
||||
| `uShadowBiasMeters.z` | Normal offset in world metres |
|
||||
| `uShadowBiasMeters.w` | Caster depth padding in world metres |
|
||||
| `uShadowTextureAndFlags.x` | Directional-depth array slot in set 2 |
|
||||
| `uShadowTextureAndFlags.y` | Active cascade count, 1–4 |
|
||||
| `uShadowTextureAndFlags.z` | Square shadow-map resolution in pixels |
|
||||
| `uShadowTextureAndFlags.w` | Flags; bit 0 means directional shadows are valid/enabled; bits 8–11 carry the fixed receiver PCF radius; remaining v1 bits are reserved and zero |
|
||||
| `uShadowLightDirectionAndSource.xyz` | Normalized direction from a lit surface toward the one authored celestial body selected for this shadow frame |
|
||||
| `uShadowLightDirectionAndSource.w` | Numerically integral selected-source kind from the table below |
|
||||
|
||||
Selected-source kinds are stable ABI values:
|
||||
|
||||
| Numeric value | Selected celestial source |
|
||||
|---:|---|
|
||||
| 0 | None / unavailable; the enabled flag must be clear |
|
||||
| 1 | Authored sun |
|
||||
| 2 | Dominant authored Dereth moon |
|
||||
| 3 | Secondary authored Dereth moon |
|
||||
|
||||
All other values are reserved. The selected source is a renderer-owned fact
|
||||
resolved from the current immutable Dereth sky frame. A pack does not identify
|
||||
sky objects by private index or create a second celestial clock. The host still
|
||||
publishes only one directional-depth array: sun and moons are alternative
|
||||
sources for the same bounded cascade work, not simultaneous shadow maps.
|
||||
|
||||
When producing a cascade, its zero-based cascade index uses the existing
|
||||
`uRenderPass` push-constant member. Consumer shaders choose a cascade from the
|
||||
eye-space distance and split values. No available selected celestial source, a
|
||||
selected source at or below its accepted horizon, no authored directional
|
||||
energy, indoors, and portal/login cover clear the enabled bit; shaders must not
|
||||
sample stale maps when it is zero. Binding 5 remains sun-specific for sun rays
|
||||
and volumetric shafts. Such passes must not substitute the selected moon
|
||||
direction for `uAtmosphereSunDirection`; when binding 6 selects a moon they
|
||||
treat its shadow map as unrelated to sun-shaft occlusion.
|
||||
|
||||
## Shared push constants
|
||||
|
||||
Every pipeline retains retail's exact shared 96-byte push-constant range. API
|
||||
v1 does not enlarge it:
|
||||
|
||||
```glsl
|
||||
layout(push_constant) uniform AcdreamPushBlock {
|
||||
mat4 viewProjection; // byte 0
|
||||
int drawIdOffset; // byte 64
|
||||
int lightingMode; // byte 68
|
||||
int renderPass; // byte 72
|
||||
int lightDebug; // byte 76
|
||||
uint textureIndexA; // byte 80
|
||||
uint textureIndexB; // byte 84
|
||||
float paramA; // byte 88
|
||||
float paramB; // byte 92
|
||||
} acdreamPush;
|
||||
```
|
||||
|
||||
Pack shader source may use the logical aliases `uTextureIndexC` and
|
||||
`uTextureIndexD`. The host stores their uint slot bits in the existing
|
||||
`paramA` and `paramB` words, and the shared Vulkan preamble exposes them as
|
||||
`floatBitsToUint(acdreamPush.paramA)` and
|
||||
`floatBitsToUint(acdreamPush.paramB)`. This is an exact bit reinterpretation,
|
||||
not numeric float conversion. Pack pass scalar/vector parameters belong in
|
||||
binding 7, so the two spare retail words are available for these input slots.
|
||||
|
||||
Do not reshape existing fields. A future additive growth requires matching
|
||||
host/shader layout tests and must remain inside the 128-byte Vulkan guarantee.
|
||||
A pack pass receives scalar/vector values through binding 7. Base pipeline
|
||||
variants use `viewProjection`, draw offset, texture slots and existing mode
|
||||
fields according to that base pipeline's contract.
|
||||
|
||||
## PackSettings (set 3, binding 8, 256 bytes)
|
||||
|
||||
`RenderSettingDeclaration` values use one fixed declaration-order block:
|
||||
|
||||
```glsl
|
||||
layout(std140, set = 3, binding = 8) uniform PackSettings {
|
||||
vec4 uPackSettings[16];
|
||||
};
|
||||
```
|
||||
|
||||
The descriptor may declare at most 64 settings, which the authoring validator
|
||||
and graphical host both enforce. Setting index `i` is its zero-based position in
|
||||
`RenderPackDescriptor.Settings`; it maps to
|
||||
`uPackSettings[i / 4][i % 4]`. Declaration order is therefore shader ABI and
|
||||
must remain stable within a compatible pack version. The resolved value is one
|
||||
IEEE-754 float: Boolean is `0.0` or `1.0`, Choice is its zero-based index in
|
||||
`Choices`, and Integer/Float parse with invariant culture before float
|
||||
conversion. Integer values are limited to the exactly representable inclusive
|
||||
range -16,777,216..16,777,216; Float values must remain finite in float32. A
|
||||
matching persisted user override wins a selected-preset `SettingOverride`,
|
||||
which wins the declaration default. User values remain invariant strings keyed
|
||||
by stable pack ID plus setting ID; before candidate activation the host rejects
|
||||
unknown IDs and values that fail kind, range, step, or choice validation. That
|
||||
failure retires the complete candidate to retail with an exact reason. The host
|
||||
zero-initializes the complete block, so unused slots and any value that fails
|
||||
defensive parsing are `0.0`; ordinary descriptor/selection validation prevents
|
||||
invalid values from reaching the bind.
|
||||
|
||||
Binding 7 remains pass-local host dynamics and filter parameters. It must not
|
||||
be overloaded with pack settings: doing so would make the same setting occupy
|
||||
different components in different passes and would prevent one stable public
|
||||
mapping. This fixed block is the complete v1 contract because it adds no
|
||||
descriptor handles, storage buffers, per-frame managed callbacks, or
|
||||
pass-specific setting schemas.
|
||||
|
||||
## Logical semantic table
|
||||
|
||||
The descriptor must list every semantic the shader reads. Listing a semantic
|
||||
does not guarantee device support; the corresponding `RenderCapability` must
|
||||
also be required when the table says so.
|
||||
|
||||
| `RenderSemanticInput` | Logical shader value | Source / lifetime | Capability prerequisite |
|
||||
|---|---|---|---|
|
||||
| `WorldColor` | Sampled main-world colour slot, excluding retained UI and private viewports | `textureIndexA-D` into set 2; current main-world frame | `MainWorldColorIntermediate` |
|
||||
| `SceneDepth` | Sampled main-world depth slot plus reconstruction matrix | `textureIndexA-D` and binding 5; current main-world frame | `SceneDepthSampling` |
|
||||
| `SceneNormals` | Sampled main-world normal slot | `textureIndexA-D` into set 2; current main-world frame | `SceneNormalSampling` |
|
||||
| `SunDirection` | Normalized authored surface-to-sun direction; no second clock | Binding 5 `uAtmosphereSunDirection`; current immutable world frame | `AuthoredSunDirection` |
|
||||
| `SelectedCelestialDirectionalLight` | Normalized direction and stable source kind for the one authored sun/moon selected to cast this frame's directional shadows | Binding 6 `uShadowLightDirectionAndSource`; current immutable world/sky frame | `AuthoredCelestialDirectionalLight` |
|
||||
| `SunScreenPosition` | Authored sun projected for the main-world viewport, plus valid/in-front state | Binding 5; current camera/world frame | `AuthoredSunScreenPosition` |
|
||||
| `ActiveDayGroup` | AC's categorical group plus descriptor-declared group/elevation multipliers | Binding 5 `uAtmospherePolicy`; current Runtime environment frame | `AuthoredWeather` |
|
||||
| `Weather` | Numeric `WeatherKind`, intensity and outdoor state | Binding 5 `uAtmosphereWeather`; current Runtime environment frame | `AuthoredWeather` |
|
||||
| `CameraMatrices` | Main-world view-projection and inverse, or directional cascade transforms required by the hook | Push `viewProjection` + binding 5 inverse; binding 6 for cascades | None beyond the hook's feature capability |
|
||||
| `ShadowCasterTransforms` | Exact existing per-instance/per-part transforms for retained eligible casters | Inherited base-pipeline set-0 ABI; current retained scene | `AnimatedCasterTransforms` |
|
||||
| `DirectionalShadowMaps` | Directional-depth table slot, active cascade count, matrices, splits and valid state | Binding 6 plus set 2; current outdoor shadow frame | `DirectionalShadowMaps` |
|
||||
| `FrameTime` | Monotonic frame delta in seconds; never a gameplay clock | Binding 5 `uAtmosphereWeather.z`; current frame | None |
|
||||
|
||||
Pack-declared `ResourceReads` are resolved deterministically to the pass input
|
||||
slots supplied by the host; v1 exposes up to four sampled inputs through
|
||||
`textureIndexA-D`. `DirectionalShadowMaps` uses the binding-6 texture slot and
|
||||
does not consume A-D. Slot assignment first walks sampled-image entries in
|
||||
`SemanticInputs` declaration order (`WorldColor`, `SceneDepth`, and
|
||||
`SceneNormals` when present), then sampled `ResourceReads` declaration order.
|
||||
The first input receives A, then B, C, and D. Duplicate inputs are invalid. The
|
||||
pack never chooses a global texture-table index. Resource IDs describe graph
|
||||
edges, not binding numbers. `ResourceWrites` are render targets chosen by the
|
||||
host and are not simultaneously sampled by the same pass.
|
||||
|
||||
`RenderResourceKind.Buffer`, `RenderFormatClass.StructuredData`, and
|
||||
`RenderResourceUsage.Storage` are reserved for an additive future contract.
|
||||
They have no public v1 descriptor binding and the v1 authoring validator
|
||||
rejects them instead of accepting an unbindable graph. V1 image arrays are
|
||||
reserved for `DirectionalDepth`; ordinary colour intermediates are `Image2D`.
|
||||
Each pass writes at most one declared attachment. A zero-write pass is valid
|
||||
only at `ToneMap` or `AfterToneMapBeforePrivateViewports`, where the host-owned
|
||||
main-world target is implicit.
|
||||
|
||||
## Texture-table sampling
|
||||
|
||||
Vulkan pack SPIR-V targets the same global table as retail shaders:
|
||||
|
||||
```glsl
|
||||
#extension GL_EXT_nonuniform_qualifier : require
|
||||
layout(set = 2, binding = 0) uniform sampler2DArray uTextures[];
|
||||
|
||||
vec4 sample2D(uint slot, vec2 uv) {
|
||||
return texture(uTextures[nonuniformEXT(slot)], vec3(uv, 0.0));
|
||||
}
|
||||
```
|
||||
|
||||
An ordinary 2-D texture is a one-layer array at layer zero. Array resources use
|
||||
their declared layer. Directional depth may be sampled as ordinary depth and
|
||||
compared/filtered in shader according to the declared shadow policy; the pack
|
||||
does not create a private sampler or descriptor. `0xFFFFFFFFu` is the
|
||||
unassigned texture-slot sentinel and must be checked before sampling an
|
||||
optional input.
|
||||
|
||||
## Hooks and availability
|
||||
|
||||
| `RenderPassHook` | Inputs valid at the hook | Output boundary |
|
||||
|---|---|---|
|
||||
| `ShadowDepthBeforeWorld` | Camera/selected celestial source/environment, cascade block, retained caster transforms | Declared directional-depth resources only; outdoor gating applies |
|
||||
| `AtmosphereBeforeToneMap` | HDR world colour when required, depth/normals when required, authored atmosphere and earlier declared resources | HDR pack intermediates; rays/shafts composite here |
|
||||
| `ToneMap` | HDR world colour and earlier atmosphere resources | Main-world display colour |
|
||||
| `AfterToneMapBeforePrivateViewports` | Tonemapped main-world colour and declared resources | Main world only; private viewports and retained UI remain outside |
|
||||
|
||||
Pass order is the descriptor order within a hook and never moves backward
|
||||
through this table. Discovery does not bind any of these blocks. Bindings exist
|
||||
only in the fully validated candidate and retire through normal frame-flight
|
||||
fences on fallback, resize, portal, reconnect, unload, or the teardown phase of
|
||||
device recreation. Recreation means a complete renderer/context/device
|
||||
teardown followed by a fresh context/device; it is not live recovery from
|
||||
`VK_ERROR_DEVICE_LOST`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue