Skip to main content

Renderer

Struct Renderer 

Source
pub struct Renderer { /* private fields */ }
Expand description

Owns the GPU context, the built-in systems, and the loaded presets; renders one frame per call by evaluating the active preset into the active system.

Implementations§

Source§

impl Renderer

Source

pub fn capture_frame( &mut self, frame: &AnalysisFrame, ) -> Result<CaptureImage, RenderError>

Advance the scene clock one step and capture that single frame into an offscreen texture, returning tight RGBA (Plan 0013). Off the hot path — blocks on GPU readback; never call it from a live loop.

Source

pub fn capture_preset( &mut self, name: &str, frame: &AnalysisFrame, frames: u32, ) -> Result<CaptureImage, RenderError>

Capture preset name after advancing it frames steps from a fixed initial state, driven by a single constant frame (Plan 0013). A pure function of (name, frame, frames): the scenes are rebuilt so any stateful system (e.g. the seeded swarm particles) starts from its deterministic seed, and the scene clock resets to 0.0, so the result is independent of any earlier capture. Errors if name is not in the roster. frames is treated as at least 1.

Source

pub fn capture_preset_over( &mut self, name: &str, stimulus: &[AnalysisFrame], ) -> Result<Vec<CaptureImage>, RenderError>

Capture preset name across a time-varying stimulus (Plan 0037): one rendered frame per entry of stimulus, read back in order, so the returned images are the response while it changes rather than after it settles.

This is the primitive capture_preset cannot be: holding one frame for every step converges every smoother before the pixels are read, which makes the result identical for any [smoothing] constant (ADR-0039). capture_preset is left exactly as it was — four suites and --report consume it — and this is its sibling, sharing the same reset_for_capture seed so both are pure functions of their arguments.

The clock advances one FALLBACK_DT per entry, so index i is second i * dt of the response. An empty stimulus yields no images. Errors if name is not in the roster.

Off the hot path, and more so than its sibling — it blocks on a GPU readback per frame, not once per call. The target and readback buffer are allocated up front rather than per frame, because building GPU resources mid-sequence perturbs what the feedback stages resolve to on the DX12 software adapter.

Source

pub fn capture_preset_at( &mut self, name: &str, frame: &AnalysisFrame, at_frames: &[u32], ) -> Result<Vec<CaptureImage>, RenderError>

Advance preset name under a single constant frame and read back only the frames named in at_frames (Plan 0085 Phase 1) — the long-run primitive, and the one a horizon needs.

Its two siblings cannot serve a run of tens of thousands of frames: capture_preset reseeds from scratch on every call, so sampling k points costs O(k·N) renders, and capture_preset_over reads back every frame, so a ten-minute run at 720p would materialize ~36,000 images. This renders N frames once and holds at_frames.len() of them.

Frame numbering matches capture_audio: frame 0 is the first advanced frame, so at_frames = [n - 1] returns exactly what capture_preset(name, frame, n) returns — asserted in core/tests/capture_advance.rs rather than argued, because it is the property that lets a horizon’s rows be compared with every other capture this repo takes.

Deterministic on the same terms as its siblings: scenes are rebuilt to their seed, the clock resets to 0.0, and the step is a fixed FALLBACK_DT — so a row at index k does not depend on how far the run was asked to go. Images come back in at_frames order; a repeated index yields the same frame twice rather than rendering it twice. An empty at_frames renders nothing.

Off the hot path — it blocks on a GPU readback per requested frame. The readback buffer is built once, at the first requested frame, and reused for every later one. Both halves of that matter on the DX12 software adapter, where building GPU resources mid-sequence perturbs what the feedback stages resolve to (the hazard capture_preset_over documents, and a horizon is precisely a long feedback sequence): reusing it means the perturbation happens once rather than per sample, and doing it at the first sample rather than up front is what puts the allocation at the same point in the sequence capture_preset puts it — which is what makes the two agree pixel-for-pixel on WARP as well as on hardware. It also stays independent of the horizon requested, since the first sample sits at the same frame index however long the run is.

Source

pub fn capture_stream( &mut self, name: &str, frames: u32, dt: f32, analysis: &mut dyn FnMut(u32) -> AnalysisFrame, sink: &mut dyn FnMut(u32, &CaptureImage) -> Result<(), String>, ) -> Result<(), RenderError>

Render preset name for frames frames at an injected dt, handing each frame to sink the moment it is read back (Plan 0101 / ADR-0114) — the streaming primitive, and the one an offline video render needs.

Its three siblings all return a Vec<CaptureImage>, which is exactly what a video render cannot afford: a 1080p frame is 8.29 MB, so a four-minute track at 60 fps is 119 GB of retained images. Nothing is retained here — the frame is handed to sink and dropped, so the resident set of a 14,400-frame render is the same as a 100-frame one.

It is also the only capture entry point whose step is not the fixed FALLBACK_DT. A render at --fps 30 advances the scene by 1/30 s a frame, or the visuals would run at half speed against their own soundtrack; that dt is the caller’s, exactly as it is for the live frontend (ADR-0013). At 60 fps dt is FALLBACK_DT, which is what makes a rendered frame comparable with every other capture this repo takes.

analysis supplies the AnalysisFrame for each frame index. The audio hop clock and the frame clock are different clocks and only the caller knows the mapping between them, so this deliberately does not walk PCM — unlike capture_audio, which welds one rendered frame to one analysis hop.

Deterministic on the same terms as its siblings: scenes rebuilt to their seed, the clock reset to 0.0, the salt pinned. Given a deterministic analysis the whole run is a pure function of (name, frames, dt).

Off the hot path — it blocks on a GPU readback every frame, which is also what bounds its memory: read_back polls, so each frame’s submission is retired before the next is encoded (the retention Plan 0099 measured). The target and the readback buffer are built once and reused, so a long run allocates no GPU resources mid-sequence.

A sink error stops the run and comes back as RenderError::Sink carrying the consumer’s own message.

Source

pub fn capture_audio( &mut self, name: &str, pcm: &[f32], format: AudioFormat, at_frames: &[u32], ) -> Result<Vec<CaptureImage>, RenderError>

Drive preset name with real audio through the real analyzer and capture the frames at at_frames (Plan 0013). The PCM is fed hop-by-hop into a fresh Analyzer (format validated at the intake boundary — the source-agnostic rule); each produced AnalysisFrame drives one rendered frame, so at_frames indexes the hop sequence (frame 0 is the first hop). Deterministic: scenes are rebuilt to their seed and the clock resets to 0, exactly like capture_preset.

This is in-memory PCM only — no file, decoder, or OS audio-source code, just like a frontend pushing samples. Returned images are in at_frames order; an index past the audio length is an error.

Source

pub fn capture_audio_after_warmup( &mut self, name: &str, pcm: &[f32], format: AudioFormat, at_frames: &[u32], warmup_hops: usize, ) -> Result<AudioCapture, RenderError>

capture_audio, with the first warmup_hops hops advanced but not rasterized (Plan 0084 Phase 3).

A warm-up hop still pushes its samples, still publishes its AnalysisFrame, and still advances the scene clock by one FALLBACK_DT — the hop happened, it just did not draw. What it skips is the render pass, which is why a caller that only needs the analyzer warm (core/tests/reactivity.rs drives WARMUP_HOPS of them per capture, at silence, and reads none of them back) stops paying a full rasterization per hop to reach a DSP state that needs no pixels.

This does not warm GPU-side scene state. Analysis is a pure function of its window and the render pass never touches the analyzer, so the published frames are bit-for-bit what they would have been — but a scene that integrates on the GPU (particles, trails, reaction-diffusion) has that many fewer steps behind it at the first rendered hop. Time-driven scenes are unaffected, since the clock advances either way.

An at_frames entry inside the warm-up span was never rendered and is an error, the same one an index past the audio length gives.

Source§

impl Renderer

Source

pub fn open_tap(&self) -> FrameTap

Open a FrameTap sized to this renderer’s configured target — the one GPU allocation a tapped run makes, so the per-frame path makes none.

The tap is fixed at the size it is built with. A resize underneath a live tap leaves the two disagreeing, and the tap wins: it is what render_tapped draws and copies against. Reopen after a resize to follow it.

Infallible: RenderContext floors both dimensions at 1 where the size enters, so there is nothing left to reject here.

Source

pub fn render_tapped( &mut self, tap: &mut FrameTap, frame: &AnalysisFrame, dt: f32, ) -> Result<CaptureImage, RenderError>

Advance the scene clock by dt real seconds, draw the active preset for frame through the same draw_frame the window presents through, and read the result back out of tap.

dt is per call, which is the difference between this and capture_stream’s one fixed step: a caller that falls behind the wall clock yields fewer, correctly-timed frames rather than a picture running slow against the music.

Draws under SaltMode::Live, because a tap is a live render path and not a capture: a preset declaring seed = "random" (ADR-0051) must vary per launch here exactly as it does in the window. Both salts are equal for every preset that declares anything else, which is why a tapped frame and a capture_frame of the same preset at the same clock are still byte-identical (core/tests/frame_tap.rs).

Blocks on the readback, as every path through capture::read_back does. That is what bounds a long run’s memory — the poll retires each frame’s submission before the next is encoded (the retention Plan 0099 measured) — and it is why this is a source entry point and not a display one: there is no present deadline here, only throughput.

Source§

impl Renderer

The renderer-facing half: opening and closing the readback, and the two steps a frame drawn through the intermediate performs.

Source

pub fn open_preview_readback( &mut self, width: u32, height: u32, ) -> Result<(), RenderError>

Open a non-blocking readback of the preview, yielding widthxheight frames.

Requires an open preview — the blit that fills the readback’s tap samples that intermediate and has nothing to read without one. The size is the caller’s and is answered for the life of the readback: a renderer resize rebuilds the intermediate under the blit and moves nothing here (ADR-0187).

Calling it again replaces the readback, which is how a caller changes the size it asked for.

Refused when the frames would come out at a format no consumer can be told the order of, so the announcement that follows can always be true (ADR-0187).

Source

pub fn close_preview_readback(&mut self)

Close the readback and free its staging buffer. A closed readback yields nothing and costs the frame one Option test.

Source

pub fn preview_readback_size(&self) -> Option<(u32, u32)>

The size of the frames the readback yields, or None when it is closed.

The size the caller asked for, and not the output’s. The frames are a scaled, letterboxed copy of the intermediate rather than an exact one, so this is a fixed property of the open readback: it answers the same pair across every resize, and a consumer told it once never has to be told again.

Source

pub fn take_preview_frame(&mut self) -> Option<CaptureImage>

Take the frame the readback produced, if one has landed.

A frame is available at most every other call in the steady state, and None means “not yet” rather than “never”: the caller sends what it gets and does not wait.

Source§

impl Renderer

The roster-facing half of Renderer: replacing the preset set, moving the active index, and applying the incoming preset’s structural config to its scene. An impl Renderer continuation for the same reason tier_governor is one – these read and write Roster and nothing else about the device.

Source

pub fn set_presets(&mut self, presets: Vec<Preset>)

Replace the preset roster (the standalone’s hot-reload path). An empty set is ignored so a preset directory that briefly reads empty — or whose files are all malformed — leaves the last good roster rendering (NFR 10).

Source

pub fn set_param_override( &mut self, name: &str, value: f32, ) -> Result<(), ParamError>

Hold value on name until it is cleared, shadowing whatever the active preset’s binding for it evaluates to (ADR-0176).

The name does not have to be one the preset binds: anything the active system’s vocabulary claims can be driven, and one it does not is refused here rather than dropped silently at apply time. The override survives every frame until clear_param_override, and is dropped wholesale by a preset switch and by set_presets.

Not eased. A sender moving a slider is already producing a continuous path, and a smoother between the two would make the picture lag the hand.

Source

pub fn clear_param_override(&mut self, name: &str)

Drop name’s override; its binding resumes on the next frame, easing from wherever the smoother left it rather than from the held value. A name that holds no override is a no-op.

Source

pub fn clear_param_overrides(&mut self)

Drop every override at once.

Source

pub fn cycle_preset(&mut self) -> &str

Switch to the next preset; returns its name. Dissolves rather than cuts (Plan 0023): the outgoing preset’s composite is captured on the next frame and blended out over DEFAULT_DURATION_SECS while the incoming one renders live. Every system is built at startup, so no scene is constructed here; the dissolve’s opening frames do allocate its own resources lazily — see begin_transition.

The returned name is the incoming preset’s, immediately — the frontend’s HUD should name where the show is going, not where it has been.

Source

pub fn preset_names(&self) -> impl Iterator<Item = &str>

The loaded preset names in roster order — the browse overlay’s list source (Plan 0008). Selection addresses these by absolute index.

Source

pub fn select_preset(&mut self, index: usize) -> &str

Switch to the preset at index (its absolute position in preset_names); returns the incoming name. Like cycle_preset this dissolves rather than cuts (Plan 0023 Phase 5) — the browse overlay’s select is a switch the operator watches, so it gets the same treatment as Space. An out-of-range index is a no-op (never a panic, never a wrap), so a stale index from a shrunk hot-reloaded roster is harmless.

Use select_preset_now where a blend would be wrong rather than merely unwanted.

Source

pub fn select_preset_now(&mut self, index: usize) -> &str

Jump to the preset at index with no dissolve — the instant-cut escape for paths where a blend is wrong rather than unwanted: a capture, which must stay a pure function of its inputs (NFR §6), or a test placing the roster on a known preset before measuring. Returns the now-active name; an out-of-range index is a no-op.

Source

pub fn select_preset_by_name(&mut self, name: &str) -> bool

Make the preset named name active, returning whether it was found — the by-name form of select_preset, and like it a dissolve. An unknown name leaves the active preset unchanged.

Source§

impl Renderer

Source

pub fn new( target: impl Into<SurfaceTarget<'static>>, width: u32, height: u32, opts: RendererOptions, ) -> Result<Self, RenderError>

Build a renderer drawing into target (a safe window handle — the standalone path). Starts with the embedded default presets.

opts carries the quality-tier pin and the adapter choice; RendererOptions::default() is auto (rich, governed) on whatever adapter wgpu picks for the surface.

Source

pub fn new_headless(opts: HeadlessOptions) -> Result<Self, RenderError>

Build a headless renderer that draws into offscreen textures instead of a window (Plan 0013 capture tooling). Same scenes, presets, and per-frame evaluation as the on-surface path — only the target differs. Starts with the embedded default presets.

Pinned Tier::Floor, and there is no argument to say otherwise (ADR-0045). A capture is a pure function of its inputs (NFR §6), and a baseline that moved because the machine that blessed it was fast is not a baseline — so the floor is the default by construction here rather than by every call site remembering to ask for it. Use new_headless_tiered for a deliberate rich-tier capture.

Source

pub fn new_headless_tiered( opts: HeadlessOptions, tier: Tier, ) -> Result<Self, RenderError>

A headless renderer pinned to tier — the opt-in behind the shot CLI’s --tier, for spot-checking that the rich tier’s raised budgets actually render (Plan 0044 Phase 3). Always pinned, so a capture never demotes mid-run and stays reproducible.

Source

pub fn new_headless_on( opts: HeadlessOptions, tier: Tier, adapter: &AdapterChoice, ) -> Result<Self, RenderError>

A headless renderer pinned to tier, on a named adapter (ADR-0146).

The one real headless constructor; the two above delegate here with the choice their prefer_software flag already implies, so every capture path resolves exactly the adapter it resolved before.

A live video-out needs this because the adapter is not a performance preference there: a Spout receiver can only open a sender that lives on the GPU it renders with, and on a hybrid machine a console process is handed the power-saving one. The sender’s adapter is what that constrains; this one is the renderer’s, and the two are matched by name on each side rather than by a shared index.

Source

pub fn new_headless_offline( opts: HeadlessOptions, tier: Tier, ) -> Result<Self, RenderError>

A headless renderer pinned to tier and resolving the offline sample ceiling (ADR-0140) — the one constructor shot --render reaches, and the only one in the engine that does.

Separate from new_headless_tiered rather than a flag on it, because the two answer to different bounds and only one of them may ever produce a baseline: a render walks a clip with dt injected and no display to miss, so its ceiling is memory; every other headless path is a capture, and a capture takes the live ceiling so the allocation — and with it the seeded scatter — is the one every committed baseline was blessed against.

Source

pub unsafe fn new_from_surface_target( target: SurfaceTargetUnsafe, width: u32, height: u32, ) -> Result<Self, RenderError>

Renderer targeting a surface the host owns and built the handle for — the C ABI path, and the only constructor that does not create its own surface. Starts with the embedded default presets (no ABI surface for preset selection yet).

The platform lives on the caller’s side of this seam, not here (ADR-0001, ADR-0072): the host knows what kind of window it has and builds the [wgpu::SurfaceTargetUnsafe] for it, so core stays source-agnostic and platform-free. core-cabi is the one that knows about HWND.

Auto tier: the plugin gets rich-with-governor, because the C ABI stays v4 and a plugin-side tier picker is a future ABI question rather than part of ADR-0045.

§Safety

target’s handles must be valid and must outlive this renderer.

Source

pub fn tier(&self) -> Tier

The active quality tier (ADR-0045) — what the diagnostics overlay and the shot report header name.

Source

pub fn set_tier(&mut self, tier: Tier)

Change the quality tier on the running renderer (ADR-0054).

Rebuilds the tier-dependent GPU resources — the scene roster and the composite side — against the new TierConfig, on the existing RenderContext. The device, queue, surface, preset roster, active preset, engine clock, text layer and diagnostics all survive, so the operator stays on the preset they were watching. A dissolve in flight is dropped: its two sides are GPU state built at the outgoing tier.

The visible cost is one re-accumulation of everything that accumulates — trails, reaction-diffusion state, the attractor’s deposit. That is the correct affordance rather than a defect: the operator asked for this and can see that it happened.

A no-op on a surface-less (headless) context, so ADR-0045’s by-construction guarantee that a capture is Tier::Floor survives a public mutator existing on this type at all. The condition is tier::tier_change_permitted, which is a value rather than a comment.

An explicit call pins the tier and clears the governor’s demotion latch. The latch means “the governor took a decision the operator did not ask for, and must be told about it”; once the operator has asked for something, that history is spent. ADR-0045 says the latch is never cleared — ADR-0054 narrows that to “never cleared by the governor”, and is the correction of record.

Source

pub fn active_index(&self) -> usize

The active preset’s index in the roster — what the browse overlay opens on, and what a caller checks a tier rebuild against.

Source

pub fn target_preset_index(&self) -> usize

The index the show is going to: the dissolve’s target while a transition is in flight, and active_index otherwise. This is the “where the show is going, not where it has been” convention cycle_preset already returns a name by, expressed as an index — a host checkmarking a menu wants the user’s most recent choice to be ticked immediately, not a quarter-second later.

Meaningless on an empty roster (0, like active_index); a caller that distinguishes that case reads preset_names first.

Source

pub fn tier_demoted(&self) -> bool

Whether the frame-time governor demoted this session’s tier.

The frontend reports the transition, so a demotion is announced once rather than shouted every frame — the same pattern cap_overflow is surfaced through. A pinned floor answers false; only a governed demotion sets this.

Source

pub fn set_display_hz(&mut self, hz: f32)

Tell the renderer the display’s refresh rate, which sets the frame budget the governor measures against (ADR-0045). Defaults to DEFAULT_DISPLAY_HZ; a rate that is not usable falls back to it rather than producing a degenerate budget.

Off the hot path — call it at startup and on a monitor change. The core does not read this from the platform itself: a refresh rate is a shell concern, and the whole point of the split is that core knows nothing about windows.

Source

pub fn resize(&mut self, width: u32, height: u32)

Reconfigure the surface for a new window size.

Source

pub fn open_preview(&mut self) -> Result<(), RenderError>

Open the program preview: the frame starts being drawn into an intermediate and copied to its destination, so a second consumer can sample the same pixels the show is getting.

Fails when the destination surface does not accept COPY_DST, which is the one thing that makes the copy exact. Reported rather than degraded to a sampling blit: a preview is worth less than a show whose encoded values silently changed.

Idempotent in effect — an already-open preview is rebuilt at the current size, which is also how a caller follows a resize it did not see.

Source

pub fn close_preview(&mut self)

Release the intermediate. Idempotent, and the frame path returns to drawing straight at its destination on the very next frame.

Takes any readback with it: the readback copies out of the intermediate, so one left behind would hold a staging buffer for a texture that no longer exists and never yield another frame.

Source

pub fn preview_state(&self) -> Option<((u32, u32), u64)>

The open preview’s size and identity, or None when closed.

Source

pub fn pixel_order(&self) -> Result<PixelOrder, RenderError>

The channel order every frame this renderer hands a consumer carries.

One answer for every path, because there is one source: the frame tap’s target, the capture target and the preview’s intermediate are all built at the context’s configured format, so a windowed run reports whatever the swapchain negotiated and a headless one reports HEADLESS_FORMAT. A caller announcing a frame pipe reads this instead of naming a constant — a constant is true on one of those two paths and false on the other (ADR-0187).

Err where that format has no name a consumer knows, which is a refusal to publish bytes under a guess.

Source

pub fn attach_aux( &mut self, target: impl Into<SurfaceTarget<'static>>, width: u32, height: u32, frame_latency: u32, ) -> Result<AuxPresentMode, RenderError>

Attach a secondary present target — a second window’s surface, on this renderer’s existing device (ADR-0143).

The core learns nothing about what that window is for. It presents the runs it is handed and nothing else; the shell decides their meaning. Returns the present mode the surface negotiated, so the caller can log which arm ran.

frame_latency is the secondary swapchain’s desired_maximum_frame_latency; see AuxTarget::new for what it paces and for the range it is clamped to.

An already-attached target is replaced. An Err means this adapter cannot drive that surface — the dual-GPU case — and the caller is expected to degrade rather than treat it as fatal: the show is on the primary surface, which is unaffected.

Source

pub fn aux_frame_latency(&self) -> Option<u32>

The secondary target’s configured frame latency, or None when detached.

Source

pub fn aux_counts(&self) -> Option<AuxCounts>

What the secondary target’s present path has done since it was attached, or None when detached.

The counts live with the target and die with it, so a caller that wants a session’s totals reads them before detach_aux.

Source

pub fn detach_aux(&mut self)

Release the secondary target, its swapchain and its text atlas. Idempotent.

Source

pub fn aux_attached(&self) -> bool

Whether a secondary target is currently attached.

Source

pub fn resize_aux(&mut self, width: u32, height: u32)

Resize the secondary target’s swapchain. No-op with none attached.

Source

pub fn aux_size(&self) -> Option<(u32, u32)>

The secondary target’s size in physical pixels, or None when detached.

Source

pub fn present_aux(&mut self, runs: &[TextRun<'_>]) -> Result<(), RenderError>

Draw runs on the secondary target and present it. No-op with none attached.

Deliberately not called from render: the two surfaces present independently, so a frame the output drops does not have to cost the console one, and neither surface’s state can reach the other’s.

Independent is not free. The caller decides when this runs, and in the standalone that is the display thread — so a console that stalls stalls the loop that called it, whatever the two surfaces do separately. The cost is a measurement: Plan 0147 Phase 4 put it inside noise across three frame-time regimes on an integrated Radeon, and aux_counts is what makes such a reading distinguishable from a console that never presented at all.

Source

pub fn queue_text(&mut self, runs: &[TextRun<'_>])

Queue text runs to composite over the next rendered frame; the queue is cleared after each render. The standalone fills it each frame with the active preset name and, while the browse overlay is open, its rows. A text-feature (standalone) path — the plugin/default build has no text.

Source

pub fn set_now_playing(&mut self, text: &str)

Announce the currently playing track (ADR-0110). The banner fades in, holds, and fades out on its own; the caller only says what, never when to stop.

The string is artist - title, split on the first -. Setting the string that is already set does nothing, so a metadata source may push on every update it receives. An empty string clears the banner.

Source-agnostic by construction (ADR-0001): the argument carries no evidence of whether it came from Windows SMTC or foobar’s titleformat. Callers must not call this from an audio callback — the copy allocates.

Source

pub fn enable_diagnostics(&mut self, on: bool)

Enable or disable rolling frame-time collection — the gated diagnostics clock read (Plan 0011). The standalone leaves this on so the title always shows live fps/p99; turning it off keeps the core fully clock-free.

Source

pub fn set_overlay(&mut self, on: bool)

Turn the on-screen debug overlay on or off (off by default). Independent of collection, so the plugin can log metrics without painting the overlay.

Source

pub fn overlay_enabled(&self) -> bool

Whether the debug overlay is currently painted.

Source

pub fn metrics(&self) -> Metrics

The current diagnostics snapshot (fps, p99, GPU bytes, …).

Source

pub fn frame_ms_p50(&self) -> f32

Median frame time over the diagnostics window, in milliseconds.

Native-only, beside the analysis snapshot below and for its reason: Metrics mirrors the C ABI’s RlxMetrics, so a field added there widens that surface (ADR-0052). A median beside the p99 is what makes a frame-time reading legible — typical against worst — where the mean the snapshot already carries sits between them saying neither.

Source

pub fn analysis_metrics(&self) -> AnalysisMetrics

The last drawn frame’s analysis snapshot — the levels and the downbeat lock state. Native-only: deliberately absent from the C ABI, so the foobar plugin has no counterpart (ADR-0052).

Source

pub fn preset_name(&self) -> &str

Name of the currently active preset.

Source

pub fn adapter_is_software(&self) -> bool

Whether the active GPU adapter is a CPU/software rasterizer (WARP on DX12). Visual-QA tests read this to skip differential checks the software rasterizer can’t render faithfully — notably the fullscreen-scene + background-pipeline coexistence, which WARP mis-renders while real hardware renders it correctly (Plan 0025 / ADR-0026).

Source

pub fn adapter_description(&self) -> &str

The active adapter’s description — name, backend, device type and driver.

For reports that have to name the machine they were taken on (ADR-0071): a frame time is a fact about a GPU and a driver rather than about the code, so a cost instrument that prints one has to say which. Read by core/tests/collage_cost.rs; nothing on a render path consults it.

Source

pub fn active_system_name(&self) -> &'static str

Name of the built-in system the active preset drives (e.g. the frontend shows it next to the preset name).

This is the scene’s display string — "fragment field", with a space. It is not the key anything looks a system up by; see Renderer::active_system_key, which is a different string for every system whose name is more than one word.

Source

pub fn active_system_key(&self) -> &'static str

The canonical key of the system the active preset drives — "fragment_field", the exact string a preset writes in its system field and the schema export labels that system’s parameter roster with.

Distinct from Renderer::active_system_name and not interchangeable with it: the two coincide on the four systems whose names are one word (swarm, spectrum, emitter, attractor) and differ on every other, so code that resolves a schema roster from the display name works for a quarter of the systems and silently finds nothing for the rest. Anything keyed by system takes this one (ADR-0184).

"" on an empty roster, matching its sibling.

Source

pub fn active_preset_source(&self) -> Option<&Path>

The file the active preset was read from, or None when it came from the embedded set and has no file on disk.

Absolute, as crate::preset::load_dir recorded it, so a consumer in another process can act on it.

Source

pub fn cap_overflow(&self) -> Option<&CapOverflow>

The segment-cap truncation from the active preset’s last configure, if its geometry hit the fixed cap (ADR-0007: the cap is never a silent cut). Refreshed on every active-preset change (select / cycle / hot-reload); the standalone surfaces it at load. None in the normal case where geometry fit — which is every shipped preset.

Source

pub fn render( &mut self, frame: &AnalysisFrame, dt: f32, ) -> Result<(), RenderError>

Draw the current preset for this analysis frame, advancing all animation by dt real seconds (Plan 0014 Phase 2). The frontend measures and injects elapsed wall-clock time so the visuals run at the same speed on any refresh rate; core never reads a clock. Lost/outdated surfaces self-heal by reconfiguring; timeouts/occlusion skip the frame; only a validation failure (a bug) bubbles up.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,