Fensalir/state/map.yaml
2026-05-27 20:19:05 +01:00

191 lines
13 KiB
YAML

project:
name: Fensalir
root: E:\Projects\Fensalir
upstream: https://github.com/GameCult/Fensalir.git
purpose: >
Native C# runtime and renderer dependency for Aquarium-style clients. The
engine owns Win32 hosting, D3D12 rendering, input, hot reload, debug UI,
audio output, client contracts, fractal/field machinery, and engine demos.
current_model:
solution: Fensalir.sln
host:
implementation: src/Aquarium.Engine
contracts: src/Aquarium.Engine.Contracts
renderer: src/Aquarium.Engine/Render
shaders: src/Aquarium.Engine/Render/Shaders
assets: src/Aquarium.Engine/Assets
scripts: scripts
fractal:
implementation: src/Aquarium.Engine.Fractal
tests: tests/Aquarium.Engine.Fractal.Tests
receipt_tool: tools/Aquarium.Fractal.Receipt
demos:
fensalir_splash: src/Aquarium.Fensalir
minimal: src/Aquarium.Sample.Minimal
zyphos: src/Aquarium.Zyphos
external_clients:
epiphany_aquarium: E:\Projects\Aquarium-Engine
mimir: owns the sensor-fusion app/adapter surface formerly prototyped here
dependencies:
cult_math: E:\Projects\CultMath
cult_lib: E:\Projects\CultLib
aqua_synth_faust: repo-local NuGet package feed under packages
invariants:
- Fensalir owns reusable host, renderer, audio, reload, contracts, and engine mechanisms.
- Fensalir is not a traditional rendering pipeline. It is a field/evidence
machine: contributors emit bounded Form, Appearance, and Transport claims
with identity, travel/depth, metadata, control, and reservoir-guide lanes.
Treating a pass as "just drawing pixels" violates the engine invariant
unless it is explicitly marked as a fallback/debug draw with no authority.
- Client repos own policy, role names, narrative semantics, app state, and client shaders.
- Epiphany Aquarium depends on Fensalir; Fensalir must not depend on Epiphany.
- Demo projects inside this repo are allowed to exercise engine features but must not become hidden engine policy.
- Public `Aquarium.*` assembly names remain for continuity until a deliberate namespace/package migration.
- Spline/tube visibility is owned by shader SDF evaluation. CPU geometry may
place conservative sampling envelopes and endpoint/neighbor packets, but
quad-local strip UVs must not decide visible line coverage.
- Reservoir splat rendering must not impose large minimum billboard radii on
transparent buffer-field/tube samples. Sample envelopes should stay tied to
authored field radius so clients can reduce reservoir sample count without
turning sparse probes into visible plates.
- Reservoir contents are not forced to be pixel-sized. Pixel-level resolve
samples bounded claims; it does not define their native support. Broad,
smooth surfaces may be represented by few large surface claims. Heightfield
terrain should be a quadtree of brush-painted surface tiles, subdivided by
projected footprint, curvature, brush/material detail, silhouettes, and
temporal uncertainty before SDF probes emit detail-adaptive surface splats.
- Rendering backends are lowerings, not truth owners. Heightfields, splines,
direct SDF proxies, meshes, volumes, fractal probes, and Mimir sensor
observations must publish bounded Form/Appearance/Transport field claims
before they can participate in reusable field evidence.
- Field packet payload handles are not authority. Resource-backed claims and
packets must reference declared AquariumFieldResourceDeclaration rows with
kind, GPU residency, shader access, format, shape, validity, version, and
native handle metadata. Missing, CPU-only, or backend-incompatible resources
defer lowering instead of becoming visible evidence.
- Rendering-relevant field buffers move to GPU residency as early as possible
and stay there. Fensalir must pass GPU resource handles/SRVs/UAVs between
compute and render lowerings; CPU readback or CPU tessellation is a
diagnostic-only escape hatch, not the live TubeField path.
- Audio control frames are contracts, not sample movement. Client runtimes
may publish DSP targets through `AquariumAudioDocument`, and the engine
audio host may retain the latest frame, but Faust/native streaming DSP must
own the hot fractional-delay/resampling path before any aligned-audio claim
is true.
- Streaming Faust DSP is now an engine audio mechanism. Clients declare a
profile-keyed `AquariumStreamingDspProgram`; Fensalir compiles it through
AquaSynth.Faust, keeps a persistent DSP instance, applies matching audio
control frames, and processes profile-keyed `AquariumStreamingAudioBlock`
input lanes into DSP output lanes. Optional monitor playback is explicit;
durable stem routing and OBS-facing publication remain the next host cut.
next_actions:
- Keep origin pointed at https://github.com/GameCult/Fensalir.git.
- Keep `dotnet build Fensalir.sln` green after the split.
- Cut the rendering rebuild through explicit field-domain/field-claim
contracts before adding another backend-specific visual path.
- Extend the D3D12 field packet/resource resolver beyond its first
structured/curve-buffer cut. Current contracts, DSL, and renderer registry
can validate and plan resource-backed TubeField packets, import shared GPU
structured buffers by handle, and allocate Fensalir-owned GPU-resident
slots only when Fensalir is the producer. The TubeField DSL can now express
a 2D rolling float buffer as Catmull-Rom XY tubes with modulo column
addressing, amplitude power/normalization, radius, ramp texture path, and
emission scale. D3D12 now has a TubeField compute/render lowering:
compute binds the rolling sample buffer as read-only GPU memory, emits
fixed-budget vertex/index buffers with endpoint-clamped Catmull-Rom tube
envelopes, honors declared sample stride with byte-address loads, and
records one draw batch per lowering so the TubeField pixel shader can bind
the right source row/column and resample material per pixel with the cheap
5-tap approximation. Texture2D resources are now declared as first-class
field resources. Local assets carry source URI metadata, DSL aliases, lazy
D3D12 upload, SRV binding, and TubeField ramp lookup by resource key;
shared GPU Texture2D declarations with native D3D12 handles resolve through
the same field resource registry, using Mimir video format names such as
Bgra8, Gray8, Rg8, Nv12, and LeapStereoIr as DXGI format input. The direct
Mimir MF shape is now proven at resolver level: a D3D11 NT shared
keyed-mutex BGRA texture can be opened by Fensalir's D3D12 registry as a
shader-readable Texture2D. Shared Texture2D version is content freshness,
not import identity; the registry reuses an opened shared texture when
handle, handle kind, dimensions, and format are unchanged. Imported field
resources may now carry an external producer fence handle/value; the D3D12
renderer opens and waits that fence before resource resolution and shader
sampling, giving Mimir's D3D11 MF producer a direct synchronized path.
Fensalir
also exposes the first engine-owned texture lease broker through
`AquariumRuntimeServices`: client runtimes can request keyed D3D12
Texture2D leases, receive shared texture and producer-fence handles, then
commit producer fence values so the renderer waits before shader sampling.
Raw CPU-origin single-plane frames can use the explicit broker upload lane,
which copies rows into the leased texture on the D3D12 queue and leaves copy
accounting to the client producer. Multi-plane NV12 CPU upload is rejected
until a real planar copy path exists; GPU producers can still write NV12
leases directly. This makes imported handles an edge case, not the primary
live camera authority. Missing or unresolved TubeField ramps bind a Fensalir-owned linear fallback ramp.
Camera texture claims can therefore resolve resources, but their first
visual use stays debug-view-only for now; production visual-fusion and
feature-extraction lowerings are deferred until the renderer and audio work
are fixed. TubeField compute now
emits one GPU-resident D3D12 DrawIndexed indirect argument packet per
material/resource batch, and render binds the batch source/ramp state then
executes the packet with ExecuteIndirect. The first material is opaque field
geometry with squared normalized emission, fake Fresnel center-bright/
edge-dark shaping, and requested/dispatched/truncated/indirect-draw segment
reporting. The debug field-evidence summary exposes TubeField requested,
dispatched, truncated, upload, skipped-upload, and unplanned-lowering
counts so client-side subdivision budgets can be tuned from the live
renderer result instead of guessed. SurfacePage resources now have a first
resolver: contracts and DSL can declare GPU-resident 2D pages with width,
height, format, version,
and optional local source, and the D3D12 registry allocates/imports them as
shader-readable page textures. VolumeTexture resources now have the same
first resolver shape: contracts and DSL can declare GPU-resident 3D
textures with dimensions, depth, format, and version, and the D3D12 registry
allocates them as shader-readable volume textures. Mesh resources are now
first-class packages with `Mesh.Vertices` and `Mesh.Indices` buffer members,
topology, index format, bounds, submesh count, and version. The DSL can
declare a GPU-resident mesh package, and the D3D12 registry allocates and
reuses matching vertex/index GPU buffers under the mesh resource key. The
evidence DSL also has a generic resource-backed `claim` command, so Mesh,
Height/SurfacePage, and Density/VolumeTexture resources can be planned into
backend packets without pretending a render path exists. Remaining cuts are
render lowerings that consume those packets. Mesh layout authority is now
split intentionally: imported/user-facing meshes use the standard
`PositionNormalUvColor` layout, while generated meshes may declare
`PipelinePrivate` so the selected lowering owns the minimal bytes it emits
and consumes. Mesh rendering is now blocked on choosing the first selected
render lowering/material path, not on a generic imported-mesh ABI. The
first generated-mesh render cut is TubeField itself: compute emits
pipeline-private vertex/index/indirect buffers, render binds them through a
named `D3D12PipelinePrivateGeneratedMesh`, and TubeField material state
supplies the shader-specific source/ramp/constants. The DrawIndexed indirect
command signature is now owned by the generated-mesh lane rather than
TubeField, so future generated page/volume/surface lowerings can share that
draw ABI while owning their own producer buffers and materials. TubeField
dispatch now obeys selected packet authority: only lowerings whose claim has
a planned TubeField backend packet are expanded, and unplanned lowerings are
counted instead of rendered. Validation also rejects TubeSpline lowering
metadata whose claim is not Tube-encoded or whose resource does not match
the claim payload, so split authority is caught before render dispatch.
Field evidence now carries explicit Float32 resource uploads separate from
resource declarations. D3D12 uploads those frame samples into resolved
structured buffers before TubeField compute reads them, so a Fensalir-owned
GPU resource can be live data rather than paperwork. Resource uploads carry
an explicit element offset, validation rejects out-of-range writes, and
D3D12 copies partial uploads into the declared buffer offset. Fensalir now
tracks uploaded structured-buffer columns beside the resolved resource and
clamps TubeField dispatch to the contiguous valid logical history range, so
stale or never-uploaded rolling slots cannot reach the TubeField shader as
geometry after allocation, reset, or partial update. Structured buffer
declaration version is content freshness, not buffer-shape authority:
D3D12FieldResourceRegistry now reuses an existing structured buffer when
element count, stride, and access are unchanged, updating the recorded
version without reallocating GPU memory every frame. TubeField metadata now
carries a stable field id derived from the planned claim key instead of one
flat family constant, so temporal/reprojection/reservoir consumers can
distinguish source-lane claims while preserving the TubeField family range.
- Move any remaining client-only Epiphany state found here back to `E:\Projects\Aquarium-Engine`.
- Keep Mimir app/adapters out of this repo; Fensalir may expose generic sensor-fusion contracts only.
- Package contracts/host deliberately before replacing sibling source references in client repos.