Use ring offsets for spectrum history
This commit is contained in:
parent
07198f948d
commit
b44aaac7cc
6 changed files with 26 additions and 8 deletions
|
|
@ -154,7 +154,9 @@ a named invariant that the native runtime cannot protect yet.
|
|||
topology changes do not resize the GPU buffer while the trail fills.
|
||||
`MIMIR_SPECTRUM_SOURCE_LANES` sets the lane capacity; surplus sources are
|
||||
truncated and reported in the runtime UI. Lowerings use that fixed capacity
|
||||
as `ColumnStride`, and `MIMIR_SPECTRUM_TUBE_SUBDIVISIONS` controls the
|
||||
as `ColumnStride`. Physical history slots are addressed as a ring with
|
||||
`RollingOffset`, so logical age no longer requires reshuffling every column
|
||||
before shader sampling. `MIMIR_SPECTRUM_TUBE_SUBDIVISIONS` controls the
|
||||
requested Catmull-Rom subdivision count so Fensalir's overflow report has a
|
||||
direct cost lever.
|
||||
- `MimirFensalirFieldLowering` now emits `AquariumFieldResourceDeclaration`
|
||||
|
|
|
|||
|
|
@ -391,8 +391,10 @@ its own age trail at `z = age * 0.1`. The resource advertises fixed history and
|
|||
source-lane capacities, so content updates and source topology changes do not
|
||||
resize the GPU buffer while the rolling trail fills. `MIMIR_SPECTRUM_SOURCE_LANES`
|
||||
sets the fixed lane budget; surplus sources are truncated and reported in the
|
||||
runtime UI. `MIMIR_SPECTRUM_TUBE_SUBDIVISIONS` is the runtime cost lever for
|
||||
lowering Catmull-Rom subdivision count when Fensalir reports TubeField
|
||||
runtime UI. Physical history slots are now addressed as a ring with
|
||||
`RollingOffset`, so logical age no longer requires moving every column before
|
||||
shader sampling. `MIMIR_SPECTRUM_TUBE_SUBDIVISIONS` is the runtime cost lever
|
||||
for lowering Catmull-Rom subdivision count when Fensalir reports TubeField
|
||||
truncation.
|
||||
|
||||
## Known Risks
|
||||
|
|
|
|||
|
|
@ -678,6 +678,7 @@ static int RunMimirSpectrumUploadSmoke()
|
|||
const int expectedHistoryCount = 3;
|
||||
const int expectedHistoryCapacity = 40;
|
||||
const int expectedSubdivisions = 2;
|
||||
const int expectedRollingOffset = (expectedHistoryCapacity - (expectedHistoryCount - 1)) * expectedSourceLaneCapacity;
|
||||
var plannedTubePackets = plan.Packets
|
||||
.Where(packet =>
|
||||
packet.Backend == AquariumFieldBackendKind.TubeField &&
|
||||
|
|
@ -714,6 +715,7 @@ static int RunMimirSpectrumUploadSmoke()
|
|||
item.ColumnCount == expectedHistoryCount &&
|
||||
item.ColumnStride == expectedSourceLaneCapacity &&
|
||||
item.RollingModulo == resource.Height &&
|
||||
item.RollingOffset == expectedRollingOffset &&
|
||||
item.CatmullRomSubdivisions == expectedSubdivisions &&
|
||||
Math.Abs(item.ColumnStep.Z - 0.1f) < 0.0001f &&
|
||||
string.Equals(item.RampResourceKey, ramp.ResourceKey, StringComparison.Ordinal) &&
|
||||
|
|
|
|||
|
|
@ -278,9 +278,12 @@ public sealed class MimirRuntime : IAquariumRuntime
|
|||
var sourceCount = sourceIds.Length;
|
||||
var activeColumnCount = checked(sourceCount * historyCount);
|
||||
var resourceColumnCapacity = checked(spectrumSourceLaneCapacity * SpectrumHistoryWindowCount);
|
||||
var newestHistorySlot = PositiveModulo(-historyFrames[0].Sequence, SpectrumHistoryWindowCount);
|
||||
var rollingOffset = checked(newestHistorySlot * spectrumSourceLaneCapacity);
|
||||
var samples = new float[width * resourceColumnCapacity];
|
||||
for (var historyIndex = 0; historyIndex < historyFrames.Length; historyIndex++)
|
||||
{
|
||||
var historySlot = PositiveModulo(-historyFrames[historyIndex].Sequence, SpectrumHistoryWindowCount);
|
||||
foreach (var spectrum in historyFrames[historyIndex].Spectra)
|
||||
{
|
||||
if (!sourceIndexById.TryGetValue(spectrum.SourceId, out var sourceIndex))
|
||||
|
|
@ -288,7 +291,7 @@ public sealed class MimirRuntime : IAquariumRuntime
|
|||
continue;
|
||||
}
|
||||
|
||||
var physicalColumn = historyIndex * spectrumSourceLaneCapacity + sourceIndex;
|
||||
var physicalColumn = historySlot * spectrumSourceLaneCapacity + sourceIndex;
|
||||
WriteNormalizedSpectrum(spectrum, samples.AsSpan(physicalColumn * width, width));
|
||||
}
|
||||
}
|
||||
|
|
@ -378,7 +381,7 @@ public sealed class MimirRuntime : IAquariumRuntime
|
|||
ColumnCount: historyCount,
|
||||
ColumnStride: spectrumSourceLaneCapacity,
|
||||
RollingModulo: resourceColumnCapacity,
|
||||
RollingOffset: 0,
|
||||
RollingOffset: rollingOffset,
|
||||
Origin: new Vector3(-5.0f, sourceIndex * SpectrumChannelSeparation, 0.0f),
|
||||
AxisStep: new Vector3(axisStepX, 0.0f, 0.0f),
|
||||
ColumnStep: new Vector3(0.0f, 0.0f, SpectrumWindowDepthSeparation),
|
||||
|
|
@ -451,6 +454,12 @@ public sealed class MimirRuntime : IAquariumRuntime
|
|||
}
|
||||
}
|
||||
|
||||
private static int PositiveModulo(long value, int modulo)
|
||||
{
|
||||
var remainder = value % modulo;
|
||||
return (int)(remainder < 0 ? remainder + modulo : remainder);
|
||||
}
|
||||
|
||||
private static Vector3 SpectrumCameraPosition(
|
||||
int spectrumCount,
|
||||
int windowCount,
|
||||
|
|
|
|||
|
|
@ -166,3 +166,4 @@
|
|||
{"ts": "2026-05-27T11:38:16+01:00", "type": "implementation", "status": "ok", "note": "Mimir spectrum resource declarations now use fixed history capacity instead of growing with the currently filled trail. The runtime smoke proves 48 bands x 4 source lanes x 40 history capacity = 7680 uploaded floats while only the active history count is emitted through each source lowering. This avoids frame-to-frame GPU buffer resizing while preserving the rolling age trail."}
|
||||
{"ts": "2026-05-27T11:41:00+01:00", "type": "implementation", "status": "ok", "note": "Mimir now exposes MIMIR_SPECTRUM_TUBE_SUBDIVISIONS as the first runtime cost lever for TubeField overflow. The spectrum upload smoke sets it to 2 and verifies every emitted source-lane TubeSpline lowering uses that Catmull-Rom subdivision count, so Fensalir's requested/dispatched/truncated segment report can be answered without changing code."}
|
||||
{"ts": "2026-05-27T11:47:48+01:00", "type": "implementation", "status": "ok", "note": "Mimir spectrum upload now has fixed source-lane capacity as well as fixed history capacity. MIMIR_SPECTRUM_SOURCE_LANES sets the lane budget, TubeSpline lowerings use that budget as ColumnStride, surplus sources are truncated and reported in the runtime UI, and --mimir-spectrum-upload-smoke verifies 48 bands x 8 lanes x 40 history capacity = 15360 uploaded floats while emitting only four active TubeField claims/lowerings."}
|
||||
{"ts": "2026-05-27T11:54:44+01:00", "type": "implementation", "status": "ok", "note": "Mimir spectrum history now uses true ring addressing. Physical history slots are keyed by sequence modulo the fixed history capacity, TubeSpline lowerings carry RollingOffset for newest logical age, and --mimir-spectrum-upload-smoke verifies the expected offset with the fixed 8-lane resource. This makes partial column uploads possible without changing shader sampling semantics."}
|
||||
|
|
|
|||
|
|
@ -370,9 +370,11 @@ accepted_design:
|
|||
the lane capacity; surplus sources are truncated and reported in the
|
||||
runtime UI. Lowerings use that capacity as `ColumnStride` through the
|
||||
shared Float32 resource so each active lane renders a true age trail at
|
||||
`z = age * 0.1`. `MIMIR_SPECTRUM_TUBE_SUBDIVISIONS` controls the
|
||||
Mimir-requested Catmull-Rom subdivisions so Fensalir's TubeField
|
||||
truncation report has a direct cost lever.
|
||||
`z = age * 0.1`. Physical history slots are addressed as a ring with
|
||||
`RollingOffset`, so logical age no longer requires moving every column in
|
||||
the upload matrix before shader sampling. `MIMIR_SPECTRUM_TUBE_SUBDIVISIONS`
|
||||
controls the Mimir-requested Catmull-Rom subdivisions so Fensalir's
|
||||
TubeField truncation report has a direct cost lever.
|
||||
- `config/perfect-machine.example.json` declares live owners, sensors,
|
||||
reservoir views, and runtime policy.
|
||||
- `src/Mimir.Runtime/Synchronization` now includes the Perfect Machine module
|
||||
|
|
|
|||
Loading…
Reference in a new issue