14 KiB
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.NoOpis the smallest discovery and activation conformance pack.AcDream.RenderPacks.AtmosphericTier2declares 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.ShadowsOnlyTier2demonstrates that Tier 2 is composable: it requests the same selected-celestial caster/receiver semantics without Tier-1 post-processing or volumetric shafts.
Quick start
-
Target
.NET 10and referenceAcDream.Plugin.Abstractionswith runtime copy disabled. The acdream host supplies that assembly. -
Add
plugin.json, include"kinds": ["renderPack"], and copy it beside the built entry DLL. -
Expose exactly one public, parameterless
IRenderPackPluginentry point. -
Construct immutable
RenderPackDescriptorvalues and register them fromRegister. Registration must only publish declarations; do not open assets, compile shaders, start threads, or allocate native/GPU resources. -
Supply shader bytes lazily through
IRenderPackAssets.OpenRead. Asset keys are forward-slash relative logical paths: never rooted, backslash-based, or./..traversals. -
Build and run the SDK validator:
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.0Substitute
AcDream.RenderPacks.AtmosphericTier2in 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:
.\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.
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.
| 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
Registerbut 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.
PluginApiversions the general managed plugin ABI.RenderPackApiversions 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.
The public shader-facing contracts are the
semantic binding table and
compatibility/failure guide.