Repository navigation
Description
Owner: @mbellehumeur (intended assignee — not assignable via the API without push access on this repo; needs assigning by hand)
Funded scope: OHIF / FU Berlin Set-Aside, task T3 (Aim 2.3, required)
Consumed by: OHIF viewport fidelity indicator (T6) — OHIF/Viewers#6256
Specification: viewport-fidelity/requirements.md in OHIF/Viewers#6254 — §5.5 VF-CS3D is this issue's requirement group; other VF- identifiers cited below are defined there
Summary
Cornerstone3D needs to expose, per viewport, what fidelity was requested versus what is
actually being displayed — as a defined interface with viewport events, plus example
implementations wired to the existing progressive loaders.
This is the prerequisite for the OHIF fidelity indicator (T6). It is also read directly by the
T11 measurement harness and the T18 final comparison, both of which record "current viewport
fidelity state", so it must be assertable without going through a UI.
Scope
-
A defined class and interface surface representing viewport fidelity information
(VF-CS3D-1). -
Viewport events emitted when fidelity information changes (
VF-CS3D-2). A getter alone
is not sufficient — the OHIF indicator subscribes rather than polls (VF-STATE-3), and must
update without a study reload (VF-STATE-2). -
The information carries, separately (
VF-CS3D-3):- the affected dimension — data resolution, display resolution, sampling density,
decoded extent, pixel value quantisation, transform approximation, or rendering path; - the cause — a device capability limit, a performance target, an incomplete load, or an
irreversibly lossy decode; - the quantified magnitude — per-axis decimation factors, decoded bytes, output
resolution percentage, sampling ratio. Consumers must be able to render
Decimated volume x/2, y/2, z/4orProgressive decode, 32 kB initial, not just
"reduced quality"; - whether the difference is transient or standing.
Separating dimension from cause is what lets a consumer render "showing less detail"
alongside "because this GPU cannot hold the full volume" without a combinatorial string
table. - the affected dimension — data resolution, display resolution, sampling density,
-
The transition must be observable, not just the current value. A progressive load that
completes without reaching full resolution moves from transient to standing, and that
transition is the single most important thing the indicator reports (VF-INFO-5a) — a
stalled lossy load is visually indistinguishable from one still in flight. -
Example implementation for stack progressive loading (
VF-CS3D-4). -
Example implementation for volume progressive loading (
VF-CS3D-5). -
Both examples source their settings and values from the existing progressive loaders
(VF-CS3D-6) rather than introducing a parallel configuration path. -
Readable programmatically without a UI (
VF-CS3D-7).
Relationship to ImageQualityStatus
ImageQualityStatus (FAR_REPLICATE = 1, ADJACENT_REPLICATE = 3, SUBRESOLUTION = 6,
LOSSY = 7, FULL_RESOLUTION = 8) stays exactly as it is, with its consumers unchanged
(VF-CS3D-8). It is internal to progressive image loading: per-image, numeric, ordered,
readable via cache.getImageQuality(imageId) and carried on IImage.imageQualityStatus.
The new state is per-viewport and distinguishes requested from displayed — a different
shape, not a replacement. The viewport state may draw on ImageQualityStatus as one input
among several.
Notes for implementation
Events.IMAGE_RETRIEVAL_STAGEfires fromProgressiveRetrieveImageswith detail
{stageId, numberOfFailures, numberOfImages, stageDurationInMS, startDurationInMS}— no
fidelity field — and has no OHIF subscribers today. Either its detail gains the
information or a new per-viewport event carries it.- Contributing sources of state, as those tasks land: T9 records the pre-allocation
downsample and its reason; T14 the active interaction reduction; T15 the ordered
fallback reason; T4 the device-class limits that make a cause explicable. T13, if
delivered, adds rendering-path substitution. - T14 degrades fidelity every frame during rotate, zoom and pan by design, so the state changes
at interaction rates. It must be truthful frame-by-frame; the consumer is responsible for
presenting that unobtrusively (VF-STATE-5), not the state for smoothing it. - Per-image granularity matters to consumers: the OHIF indicator reports the state of the image
currently displayed, not the worst across the display set (VF-VIS-4a).
Out of scope
- Detection, prevention, or recovery from insufficient browser memory (excluded by T9).
- The GPU taxonomy itself (T4), the level binding (T9), and the selection policy (T15).
- Any settable fidelity API. The state is queryable and observable; selection stays a
deterministic side-effect-free decision of the T15 policy. - Fidelity of overlay layers such as segmentation labelmaps — acknowledged gap, unfunded.
Verification
Unit and example-level tests in the Cornerstone3D suite: dimension, cause, magnitude and
persistence populated correctly per fixture; events fire on change; the transient→standing
transition on a load that completes lossy; state assertable without a UI.
Activity
linear commentedon Sep 4, 2026
CS-214
wayfarer3130 commentedon Sep 21, 2026
The component definition for this issue
This comment adds the component definition. It comes from the planning session for #2921, which is the producer of this state.
One change to the field list of this issue. The existing text asks for a
reduction sourcethat separates "server box-averaged level versus client-derived reduction, partial decode or slice subset". That one field mixes where the data came from with what arithmetic reduced the data. The definition below splits the field in two, because a client-derived level can be a box average or a decimation, and the indicator must clear for one and not for the other.Why this component lands first
Task T3 and task T4 are the two tasks that unblock the OHIF work. The breakdown says:
The multi-resolution work of #2921
is the producer of this state. That work is large. If this component waits for that work, then the
OHIF fidelity indicator (#6256) waits too.
Therefore this component lands as an early commit, and it lands with no consumer. The OHIF
developer can then build against the type and against the event, before the producer exists.
Scope, and the rule for a change to this document
This document has two requirement sections, and the two sections stay separate:
You can change an implementation requirement freely when a better approach appears. You change a
user requirement in two cases only: the requirement describes the behaviour wrongly, or the
intended behaviour for the user changes.
§ User requirements
VFS-U-1. The user can determine the quality of what each viewport shows.
VFS-U-2. Two viewports that show one volume report their quality independently. One viewport
can report "lossless" while the other viewport reports "lossy".
VFS-U-3. A viewport that shows reduced data at a magnification where the reduction is not
visible reports the view as lossless. The user does not get a warning that is not necessary.
VFS-U-4. The user can determine why the quality is reduced, and the user can determine
whether the quality improves later.
VFS-U-5. The user does not select the resolution, and the user does not configure the fidelity.
The software selects the resolution. This is requirement
VF-AUTOof the OHIF specification.§ Implementation requirements
Group 1 — the shape of the state
VFS-API-1. Define one type,
ViewportFidelityState. The type is a defined class or interface,and the type is not a scalar and not an enumeration.
VFS-API-2. The state is complete from the start. Add every field now, even where no
producer writes the field yet. A field that arrives later forces every consumer to change.
VFS-API-3. The state carries these fields:
dataResolutiondisplayResolutionreductionKindnone,boxAverage,decimation,partialDecode,sliceSubsetreductionSourceserverStoredLevel,clientDerived,decoderSubResolution,partialLoadmagnitudex/2, y/2, z/4causedeviceTextureLimit,memoryBudget,performanceTarget,incompleteLoad,lossyDecodetransienttruefor a reduction that ends when the interaction ends.falsefor a standing reduction.progressivesubstitutedDefaultsrenderPathIdVFS-API-4.
reductionKindis new, and P14 requires it. A decimation and a box average atone spacing have different loss. A decimation keeps the high spatial frequencies and folds them
into the signal, which a reformat shows as stair-stepping. A box average removes them. The OHIF
indicator must be able to clear for a box average and not clear for a decimation, so one level
number is not a sufficient report. This is also requirement
VOL-X-8.4.VFS-API-5.
magnitudestates a factor for each axis. A reduction is not uniform. A volume thathas an edge of 2049 voxels exceeds a limit of 2048 on one axis, and the state reports that.
Group 2 — the record, and the verdict
VFS-API-6. The state is an absolute record. The state says which data exists, at which
spacing, with which loss, and how much data is missing. The state does not say whether the view
is good enough.
VFS-API-7. A separate pure function compares an absolute record against the requirement of
one reader, and that function produces the verdict. Each render path can therefore produce a
different answer from the same record, according to what that render path can use.
VFS-API-8. VFS-API-6 and VFS-API-7 are the reason that VFS-U-2 works. Two viewports hold two
records, and the function runs once for each viewport.
VFS-API-9. An absolute record is cacheable. A verdict is not cacheable, because a 3D viewport
changes its required sampling on every frame of an interaction.
Group 3 — the event
VFS-API-10. Add
VIEWPORT_FIDELITY_CHANGEDtopackages/core/src/enums/Events.ts.VFS-API-11. A viewport fires the event when its fidelity state changes. A consumer subscribes
to the event, and a consumer does not poll.
VFS-API-12. The event carries the viewport identifier and the new state.
VFS-API-13. A transient reduction during an interaction fires the event without a debounce.
Task T14 degrades the fidelity on every frame, and the OHIF indicator must show that. This is
requirement
VF-STATE-5.VFS-API-14. The state updates without a reload of the study. This is requirement
VF-STATE-2.Group 4 — the relation to
ImageQualityStatusVFS-API-15.
ImageQualityStatusstays as the comparable summary, and the code derives thatsummary from the absolute record. Every existing
minQualityfloor continues to work.VFS-API-16.
ImageQualityStatushas five members today:FAR_REPLICATE = 1,ADJACENT_REPLICATE = 3,SUBRESOLUTION = 6,LOSSY = 7,FULL_RESOLUTION = 8. The values 2, 4 and 5 are free. You can add a value, and you can renumber agap. The values are not a stable format for storage.
VFS-API-17.
SUBRESOLUTIONdoes not mean "fewer pixels" today. Its producers return the valuewhen the bytes are not complete, or for a partial response. Nothing derives the value from
decodeLevel. Do not read the existing value as a statement about the resolution.Group 5 — the tests
VFS-API-18. Every field of VFS-API-3 is representable, and a unit test covers each field.
VFS-API-19. A test asserts the state without a user interface. The state is data, and a test
reads the data.
VFS-API-20. A test builds two viewports over one volume, and the test asserts that the two
viewports report a different verdict from the same record.
Done when
ViewportFidelityStateexists as a type, and the type carries every field of VFS-API-3.requirement, and the function returns a verdict.
VIEWPORT_FIDELITY_CHANGEDexists inenums/Events.ts, and a viewport fires the event.Out of scope
feat(core): add the viewport fidelity state, event and indicator (#2992)
feat(core): draw the original frames in the acquisition plane of a re…