diff --git a/docs/eve-program-output.md b/docs/eve-program-output.md new file mode 100644 index 0000000..2e8db5b --- /dev/null +++ b/docs/eve-program-output.md @@ -0,0 +1,59 @@ +# EVE Program Output + +## Authority Map + +- Owner: Fensalir owns the visible D3D12 program pixels. +- Inputs: Fensalir reads the current `AquariumFrame`, render plan, GPU resources, + and overlay state. +- Outputs: a named shared D3D12 `B8G8R8A8_UNorm` texture containing the completed + backbuffer for the current frame. +- Derived state: Mimir publication profiles describe the stream contract; they + do not render pixels. EVE receives decoded pixels and composites them. +- Forbidden writers: WebKit, DOM layout, browser dashboards, OBS capture, and + desktop/window capture do not own this path. +- Shared paths: local display and EVE streaming both use the same completed + Fensalir backbuffer copy. +- Deletion line: diagnostic Sunshine/Moonlight or desktop-duplication probes may + prove network/decode budget, but they are not production authority. + +## Current Mechanism + +Set these before launching the Mimir app: + +```powershell +$env:FENSALIR_PROGRAM_OUTPUT_D3D12 = "1" +$env:FENSALIR_PROGRAM_OUTPUT_NAME = "Global\MimirFensalirProgramTexture" +dotnet run --project .\src\Mimir.App\Mimir.App.csproj +``` + +Fensalir creates a shareable D3D12 texture with that name and copies the finished +backbuffer into it during the present pass. A hardware encoder process should +open that named texture, encode H.264/HEVC with GPU hardware, and send frames to +EVE's native receiver. + +`scripts/start-eve-program-output.ps1` starts the Mimir/Fensalir app with the +shared-texture output enabled and verifies the `eve` SSH target before launch. + +## Receiver Contract + +EVE owns: + +- network receive; +- hardware decode; +- texture upload/import; +- final fullscreen composite; +- touch/Pencil/sensor uplink later. + +EVE does not own: + +- dashboard DOM; +- Chromium/WebKit compatibility; +- layout parity; +- Mimir timing authority; +- OBS composition authority. + +## Smoke + +```powershell +dotnet run --project .\src\Mimir.BufferSmoke\Mimir.BufferSmoke.csproj -- --eve-program-output-contract-smoke +``` diff --git a/docs/implementation-plan.md b/docs/implementation-plan.md index 608b6c4..ffb19ec 100644 --- a/docs/implementation-plan.md +++ b/docs/implementation-plan.md @@ -28,6 +28,11 @@ a named invariant that the native runtime cannot protect yet. - Mimir public identity, branding, and Face memory. - `Mimir.slnx` with `src/Mimir.App` and `src/Mimir.Runtime`. - Fensalir host bootstrapping from `Mimir.App`. +- [[eve-program-output|EVE Program Output]] now owns the first native EVE + streaming contract: Fensalir can publish the completed D3D12 backbuffer into a + named shared texture when `FENSALIR_PROGRAM_OUTPUT_D3D12=1`, and Mimir records + the EVE-facing publication profile as a native D3D12 stream rather than a + WebKit/dashboard path. - `MimirSynchronizationHub`, `MimirRollingStreamBuffer`, stream descriptors, and `IMimirStreamSource`. - Configurable five-second default rolling buffers for local and network audio diff --git a/notes/current-system-map.md b/notes/current-system-map.md index 90077fb..d23f05d 100644 --- a/notes/current-system-map.md +++ b/notes/current-system-map.md @@ -26,6 +26,7 @@ flowchart TD N --> E["Fensalir GPU fusion + UI"] N --> F["Faust/native DSP"] E --> G["Spout2/program video"] + E --> V["EVE native shared-texture stream"] F --> H["program stems + spatial bed"] G --> I["OBS"] H --> I @@ -42,10 +43,13 @@ Ownership: - `Mimir.Runtime` owns app-level stream buffers and synchronization. - Native capture workers own device reads. - Fensalir owns dense visual fusion, material/brush/splat reconciliation, - D3D12 interop, runtime UI, and Spout2 publication. + D3D12 interop, runtime UI, Spout2 publication, and the completed backbuffer + texture copied into the EVE shared D3D12 program-output surface. - Faust/native DSP owns hot audio alignment, suppression, separation, spatialization, and stem generation. - OBS owns broadcast controls. +- EVE owns native decode/composite for its fullscreen display path; it does not + own layout, WebKit compatibility, or timing authority. Invariant: the live window is bounded, in memory, and has one timing authority. No private history outlives the rolling buffer. diff --git a/scripts/start-eve-program-output.ps1 b/scripts/start-eve-program-output.ps1 new file mode 100644 index 0000000..60e1737 --- /dev/null +++ b/scripts/start-eve-program-output.ps1 @@ -0,0 +1,47 @@ +param( + [string] $Target = "eve", + [string] $SharedTextureName = "Global\MimirFensalirProgramTexture", + [string] $Configuration = "Debug", + [string] $LogPath = "logs\eve-program-output-fensalir.log", + [string[]] $AppArguments = @() +) + +$ErrorActionPreference = "Stop" + +$repoRoot = Split-Path -Parent $PSScriptRoot +$absoluteLogPath = Join-Path $repoRoot $LogPath +$absoluteErrorLogPath = [System.IO.Path]::ChangeExtension($absoluteLogPath, ".err.log") +$logDirectory = Split-Path -Parent $absoluteLogPath +if (-not (Test-Path $logDirectory)) { + New-Item -ItemType Directory -Path $logDirectory | Out-Null +} + +Write-Host "Checking EVE SSH target: $Target" +ssh $Target "uname -a >/tmp/mimir-eve-program-output-check.txt && cat /tmp/mimir-eve-program-output-check.txt" + +$env:FENSALIR_PROGRAM_OUTPUT_D3D12 = "1" +$env:FENSALIR_PROGRAM_OUTPUT_NAME = $SharedTextureName + +$projectPath = Join-Path $repoRoot "src\Mimir.App\Mimir.App.csproj" +$dotnetArgs = @( + "run", + "--project", + $projectPath, + "-c", + $Configuration, + "--" +) + $AppArguments + +Write-Host "Starting Mimir/Fensalir with shared D3D12 output: $SharedTextureName" +Write-Host "Log: $absoluteLogPath" +$process = Start-Process -FilePath "dotnet" ` + -ArgumentList $dotnetArgs ` + -WorkingDirectory $repoRoot ` + -RedirectStandardOutput $absoluteLogPath ` + -RedirectStandardError $absoluteErrorLogPath ` + -WindowStyle Hidden ` + -PassThru + +Write-Host "Started PID $($process.Id). Poll with:" +Write-Host " Get-Content -Tail 40 '$absoluteLogPath'" +Write-Host " Get-Content -Tail 40 '$absoluteErrorLogPath'" diff --git a/src/Mimir.BufferSmoke/Program.cs b/src/Mimir.BufferSmoke/Program.cs index fe3617b..b018972 100644 --- a/src/Mimir.BufferSmoke/Program.cs +++ b/src/Mimir.BufferSmoke/Program.cs @@ -84,6 +84,11 @@ if (args.Any(arg => string.Equals(arg, "--perfect-machine-profile-smoke", String return RunPerfectMachineProfileSmoke(); } +if (args.Any(arg => string.Equals(arg, "--eve-program-output-contract-smoke", StringComparison.OrdinalIgnoreCase))) +{ + return RunEveProgramOutputContractSmoke(); +} + if (args.Any(arg => string.Equals(arg, "--perfect-machine-contract-smoke", StringComparison.OrdinalIgnoreCase))) { return await RunPerfectMachineContractSmokeAsync( @@ -423,6 +428,32 @@ static int RunChirpletSelfTest() return 0; } +static int RunEveProgramOutputContractSmoke() +{ + var output = MimirEveProgramOutputConfigurations.NativeSharedTexture; + var publication = MimirObsPublicationConfigurations.EveNativeProgram; + Console.WriteLine( + $"eve-output id={output.Id} host={output.TargetHost} port={output.TargetPort} texture=\"{output.SharedTextureName}\" {output.TargetWidth}x{output.TargetHeight}@{output.TargetFramesPerSecond} transport={output.Transport} webkit={output.UsesWebKit} diagnostic={output.DiagnosticOnly}"); + Console.WriteLine( + $"eve-publication id={publication.Id} videoKind={publication.VideoKind} source=\"{publication.VideoSourceName}\" diagnostic={publication.DiagnosticOnly}"); + foreach (var requirement in output.RequiredEnvironment) + { + Console.WriteLine($"eve-env {requirement}"); + } + + if (output.UsesWebKit || + output.DiagnosticOnly || + output.Transport != MimirEveProgramOutputTransport.D3D12SharedTextureHardwareEncode || + publication.VideoKind != MimirObsVideoPublicationKind.EveNativeD3D12Stream || + !string.Equals(output.SharedTextureName, publication.VideoSourceName, StringComparison.Ordinal)) + { + Console.Error.WriteLine("EVE program output contract is split-brained."); + return 1; + } + + return 0; +} + static int RunChirpBinSelfTest() { var timeline = MimirChirpBinTimeline.Default; diff --git a/src/Mimir.Runtime/Synchronization/MimirEveProgramOutputConfiguration.cs b/src/Mimir.Runtime/Synchronization/MimirEveProgramOutputConfiguration.cs new file mode 100644 index 0000000..d85e43f --- /dev/null +++ b/src/Mimir.Runtime/Synchronization/MimirEveProgramOutputConfiguration.cs @@ -0,0 +1,64 @@ +namespace Mimir.Runtime.Synchronization; + +public enum MimirEveProgramOutputTransport +{ + D3D12SharedTextureHardwareEncode, + SunshineMoonlightProbe, + DesktopDuplicationDiagnostic +} + +public sealed record MimirEveProgramOutputConfiguration( + string Id, + string Description, + string TargetHost, + int TargetPort, + string SharedTextureName, + int TargetWidth, + int TargetHeight, + int TargetFramesPerSecond, + MimirEveProgramOutputTransport Transport, + bool UsesWebKit, + bool DiagnosticOnly, + string[] RequiredEnvironment, + string Notes); + +public static class MimirEveProgramOutputConfigurations +{ + public const string DefaultSharedTextureName = "Global\\MimirFensalirProgramTexture"; + + public static MimirEveProgramOutputConfiguration NativeSharedTexture { get; } = new( + "eve-native-d3d12-hardware-stream", + "Production direction: Fensalir copies the completed D3D12 backbuffer into a named shared texture; a hardware encoder consumes that texture and EVE displays decoded frames natively.", + "eve", + 44044, + DefaultSharedTextureName, + 1920, + 1440, + 60, + MimirEveProgramOutputTransport.D3D12SharedTextureHardwareEncode, + UsesWebKit: false, + DiagnosticOnly: false, + RequiredEnvironment: + [ + "FENSALIR_PROGRAM_OUTPUT_D3D12=1", + $"FENSALIR_PROGRAM_OUTPUT_NAME={DefaultSharedTextureName}" + ], + "EVE owns decode/composite only. It does not own layout, DOM, timing authority, or Chromium compatibility."); + + public static MimirEveProgramOutputConfiguration MoonlightProbe { get; } = NativeSharedTexture with + { + Id = "eve-moonlight-probe", + Description = "Latency probe only: Sunshine/Moonlight can validate network and decode budget before the custom encoder path is finished.", + Transport = MimirEveProgramOutputTransport.SunshineMoonlightProbe, + SharedTextureName = "", + DiagnosticOnly = true, + RequiredEnvironment = [], + Notes = "This proves the EVE display/network budget, not Mimir's shared-texture authority." + }; + + public static IReadOnlyList BuiltIn { get; } = + [ + NativeSharedTexture, + MoonlightProbe + ]; +} diff --git a/src/Mimir.Runtime/Synchronization/MimirObsPublicationConfiguration.cs b/src/Mimir.Runtime/Synchronization/MimirObsPublicationConfiguration.cs index 35a8edc..f18ad49 100644 --- a/src/Mimir.Runtime/Synchronization/MimirObsPublicationConfiguration.cs +++ b/src/Mimir.Runtime/Synchronization/MimirObsPublicationConfiguration.cs @@ -4,6 +4,7 @@ public enum MimirObsVideoPublicationKind { Spout2, SharedD3D12Texture, + EveNativeD3D12Stream, SrtDiagnosticBridge, WindowCaptureDiagnostic } @@ -74,10 +75,20 @@ public static class MimirObsPublicationConfigurations TargetPresentationDelaySeconds: 1.5, DiagnosticOnly: true); + public static MimirObsPublicationConfiguration EveNativeProgram { get; } = NativeProgram with + { + Id = "eve-native-d3d12-stream", + Description = "EVE-facing native program output: Fensalir publishes a shared D3D12 texture for hardware encode; EVE receives decoded pixels without WebKit layout authority.", + VideoKind = MimirObsVideoPublicationKind.EveNativeD3D12Stream, + VideoSourceName = MimirEveProgramOutputConfigurations.DefaultSharedTextureName, + DiagnosticOnly = false + }; + public static IReadOnlyList BuiltIn { get; } = [ NativeProgram, TextureInteropProgram, + EveNativeProgram, DiagnosticSrtBridge ]; } diff --git a/state/evidence.jsonl b/state/evidence.jsonl index 0150da4..ed4fffa 100644 --- a/state/evidence.jsonl +++ b/state/evidence.jsonl @@ -119,3 +119,4 @@ {"ts": "2026-05-25T13:56:03+01:00", "type": "decision", "status": "ok", "note": "Fensalir spectrum visualization authority split: Mimir now emits AquariumBufferFieldFrame spline tube fields as the real buffer-domain contract, with tangent/curvature/normal/derivative appearance and probe policy for future compute SDF splat reservoir lowering. AquariumSplineFrame remains only the immediate Catmull-Rom preview witness until compute lowering owns rendering."} {"ts": "2026-05-25T15:55:00+01:00", "type": "decision", "status": "ok", "note": "Fensalir/Mimir spectrum visualization moved from C# spline authority to DSL-authored texture field authority. config/mimir-spectrum-field.aquafield binds a rolling spectrum texture, declares surface graph nodes, and asks for texture-dimension splinefield lowering. Fensalir now compiles Aquarium field DSL text, uploads texture samples/program packets, and ProgramMode=3 in D3D12FractalReservoirCompute emits stochastic reservoir splats from the texture field. Current canary is mechanically through the reservoir at 131072 splats with low CPU record time, but visual framing/material is still not the final beautiful spectrum surface."} {"ts": "2026-05-25T17:43:25+01:00", "type": "decision", "status": "ok", "note": "Fensalir direct splinefield correction: texture-derived tube trails are direct SDF envelope surfaces, not point-splat fractal dust. AquariumFieldScriptCompiler supports direct; D3D12Renderer now derives AquariumSplineFrame tube-envelope trails from BufferFieldFrame texture spline programs, the spline pipeline declares triangle topology, and D3D12SplinePS writes color, metadata/control, and reservoirGuide outputs. Mimir capture artifacts/runtime/mimir-direct-sdf-tube-spectrum.png proves the DSL-authored ASIO spectrum appears through the direct SDF tube path with ~0.64 ms record CPU in the canary."} +{"ts": "2026-05-25T18:01:04+01:00", "type": "decision", "status": "ok", "note": "EVE native program output is now a D3D12 shared-texture contract: Fensalir owns completed backbuffer pixels and publishes Global\\MimirFensalirProgramTexture when FENSALIR_PROGRAM_OUTPUT_D3D12=1; Mimir records the EVE publication profile and WebKit remains forbidden as pixel/layout authority."} diff --git a/state/map.yaml b/state/map.yaml index 0ae93ef..af9713e 100644 --- a/state/map.yaml +++ b/state/map.yaml @@ -46,7 +46,10 @@ invariants: to line up feeds and crunch data before OBS-facing output is emitted. - Typed views may index the rolling buffer, but no per-kind ring owns retention. - - Fensalir owns production UI, GPU fusion, D3D12 interop, and Spout2 output. + - Fensalir owns production UI, GPU fusion, D3D12 interop, Spout2 output, and + the EVE shared D3D12 program-output texture. + - EVE fullscreen output must use native decode/composite over Fensalir-owned + program pixels; WebKit/DOM layout is forbidden as pixel authority. - Faust/native DSP owns hot audio alignment, separation, spatialization, and stems. - Local secrets remain untracked. @@ -63,6 +66,11 @@ accepted_design: direct native ingest, process bridge ingest, and video capture driver seams. - `MimirVideoFrameDescriptor` carries width, height, pixel format, stride, device timestamp, and optional native/GPU handle. + - `MimirEveProgramOutputConfigurations.NativeSharedTexture` records the + EVE-facing program-output contract: Fensalir publishes + `Global\MimirFensalirProgramTexture` when + `FENSALIR_PROGRAM_OUTPUT_D3D12=1`; EVE receives decoded native pixels and + owns only final composite/input uplink. - `MimirAudioBlockDescriptor` carries sample rate, channels, sample format, frame count, timestamp, and optional native handle. - `MimirFrameEventProcessStreamSource` is a temporary diagnostic adapter for