MilkRenderer

Struct MilkRenderer 

Source
pub struct MilkRenderer {
Show 14 fields gpu: GpuContext, chain: RenderChain, secondary: Option<RenderChain>, final_blend: FinalBlendPipeline, warp_mesh: WarpMesh, state: RenderState, secondary_state: Option<RenderState>, shader_compiler: ShaderCompiler, texture_pool: TexturePool, sprite_pipeline: SpritePipeline, sprite_pool: SpritePool, sprite_frames: Vec<SpriteFrame>, text_pipeline: TextPipeline, text_frames: Vec<TextFrame>,
}
Expand description

Main Milkdrop renderer.

Orchestrates one or two RenderChains plus the final-blend pipeline that composites their final_texture outputs into a single display target. During a preset transition, the secondary chain is Some and holds the outgoing preset’s full pipeline; outside transitions it is None and the blend pass passes the primary chain straight through.

Fields§

§gpu: GpuContext§chain: RenderChain

Primary rendering chain — the currently active preset.

§secondary: Option<RenderChain>

Secondary chain, active only during a preset transition. Holds the outgoing preset’s state so it can keep evolving while the new preset takes over the primary slot.

§final_blend: FinalBlendPipeline

Final blend pass: lerps primary↔secondary final_texture into the display target by the transition progress. Passthrough of primary when no secondary chain is active.

§warp_mesh: WarpMesh§state: RenderState

Primary chain’s per-frame state (motion, wave, decay, gamma, audio, q1..q32, …). Pushed by the engine via update_state.

§secondary_state: Option<RenderState>

Secondary chain’s per-frame state. Populated by the engine during preset transitions; None outside transitions. Each chain has its own gamma_adj / echo_alpha / audio / time — they advance independently while the blend pass crossfades their final_texture outputs.

§shader_compiler: ShaderCompiler

Caches translated/validated user comp shaders by HLSL source. Letting the renderer own it keeps the codegen surface inside the crate that already depends on it; the engine just hands HLSL bytes over.

§texture_pool: TexturePool

User textures loaded from disk. Empty by default; the engine layer (GUI / CLI) populates it via set_texture_pool. The fallback 1×1 white inside the pool is bound into any unfilled user-texture slot so the comp pass produces correct output for presets whose textures we don’t have on disk.

§sprite_pipeline: SpritePipeline

Sprite GPU pipeline (MILK_IMG.INI overlay). Shared by both chains during transitions — the pipeline is stateless past init, and the sprite frames the engine pushes are global, not per-preset.

§sprite_pool: SpritePool

Sprite texture pool: one texture per loaded MILK_IMG.INI entry, indexed by SpriteFrame::texture_index.

§sprite_frames: Vec<SpriteFrame>

Sprite render instances the engine pushed via Self::update_sprites for the next frame. Cleared on every render so a stale list doesn’t outlive the engine tick.

§text_pipeline: TextPipeline

Text overlay (MILK_MSG.INI + MPRIS auto-title) pipeline. Renders on top of the final-blend output so messages never participate in the warp feedback loop.

§text_frames: Vec<TextFrame>

Text frames the engine pushed via Self::update_text_frames for the next render call.

Implementations§

Source§

impl MilkRenderer

Source

pub async fn new(config: RenderConfig) -> Result<Self>

Create a new renderer that owns its GPU device.

Source

pub fn from_gpu_context(gpu: GpuContext) -> Result<Self>

Create a renderer atop a shared GPU context.

Source

pub fn set_texture_pool(&mut self, pool: TexturePool)

Swap in a populated TexturePool. The engine layer (GUI / CLI) calls this after constructing the renderer if the user has a texture directory configured. Pool population is best-effort (missing dirs are silently empty); see TexturePool::from_dirs.

Source

pub fn texture_pool(&self) -> &TexturePool

Borrow the texture pool. Used by the GUI’s HUD to display “X user textures loaded” and by tests to assert pool wiring.

Source

pub fn gpu_device(&self) -> Arc<Device>

Borrow the underlying GPU device. Exposed so the engine layer can build a TexturePool before swapping it into the renderer.

Source

pub fn gpu_queue(&self) -> Arc<Queue>

Borrow the underlying GPU queue. Mirror of gpu_device for the pool-construction path.

Source

pub fn render_format(&self) -> TextureFormat

Format of the display texture that [read_render_texture] returns. Offline callers (CLI render-to-PNG, snapshot tests) use this to decide whether to swizzle BGRA → RGBA before encoding.

Source

pub fn render_size(&self) -> (u32, u32)

Render-target width × height in pixels. Mirrors RenderConfig.

Source

pub fn set_user_comp_shader(&mut self, hlsl: Option<&str>) -> Result<bool>

Install (or remove) the user comp shader for the active preset.

Pass Some(hlsl) from the preset’s comp_shader block to swap the comp pass into the user-authored pipeline. Pass None (or an empty &str after trimming) to revert to the engine’s gamma-only default — the fallback for presets without a custom composite or for preset loads where the translation/validation chain failed.

Return value:

  • Ok(true) — user shader compiled and is now active.
  • Ok(false) — translation or validation failed; the comp pipeline is now on the default fallback. Not an error from the renderer’s perspective; the caller can surface a log line.
  • Err(_) — the wgpu device rejected the validated shader. Rare; indicates either a wgpu/naga version skew or a pipeline-construction bug.
Source

pub fn set_user_comp_shader_for_preset( &mut self, hlsl: Option<&str>, preset_id: &str, ) -> Result<bool>

Same as Self::set_user_comp_shader, but lets the engine pass a preset_id that seeds the deterministic sampler_rand0X pick for this preset. Use the preset filename ("Geiss - Aerial.milk") or any string stable for the preset’s lifetime — same string → same rand selection.

Source

fn build_texture_plan( &self, refs: &[UserSamplerRef], preset_id: &str, ) -> (TextureBindingPlan, [Option<TextureView>; 8])

Resolve a list of sampler sampler_X; references against the texture pool into a TextureBindingPlan + a parallel array of wgpu::TextureView slot bindings for the comp pipeline.

  • Literal logical names ("clouds", "worms") are looked up by exact pool match.
  • sampler_rand0X (with optional name-prefix suffix) is resolved to a deterministic-per-preset pick from the pool, optionally filtered by the suffix.
  • Unresolvable names fall back to the 1×1 white texture.
Source

fn resolve_logical_texture( &self, logical: &str, preset_id: &str, ) -> Option<Arc<UserTexture>>

Resolve one logical texture name (e.g. "clouds", "rand02_smalltiled") to a concrete crate::UserTexture in the pool. sampler_rand0X[_prefix] patterns become deterministic picks seeded by the preset id; literal names are exact pool lookups.

Source

pub fn has_user_comp_shader(&self) -> bool

Whether the comp pass is currently driven by a user-authored shader (vs. the engine’s gamma-only fallback). Surfaced for tests and the GUI’s debug overlay.

Source

pub fn set_user_warp_shader(&mut self, hlsl: Option<&str>) -> Result<bool>

Swap in a user-translated warp shader. Mirror of Self::set_user_comp_shader_for_preset but for the warp pass. The translation goes through the same TextureBindingPlan scan + texture-pool resolution as the comp side.

Source

pub fn set_user_warp_shader_for_preset( &mut self, hlsl: Option<&str>, preset_id: &str, ) -> Result<bool>

Same as Self::set_user_warp_shader, with a preset_id that seeds the deterministic sampler_rand0X picks (filename works).

Source

pub fn has_user_warp_shader(&self) -> bool

Whether the warp pass is currently driven by a user-authored shader.

Source

pub fn update_state(&mut self, state: RenderState)

Update render state.

Source

pub fn warp_mesh(&self) -> &WarpMesh

Borrow the warp mesh for per-vertex equation evaluation.

Source

pub fn set_mesh_size(&mut self, cols: u32, rows: u32)

Rebuild the warp mesh at a different cols × rows. Reallocates the warp pipeline’s vertex/index buffers on both the primary and (if active) secondary chains. The per-vertex equation executor in the engine reads warp_mesh() every frame and allocates its output vector fresh, so it adapts without further plumbing.

cols and rows are clamped to >= 2 to match WarpMesh::new. MD2 caps nMeshSize at 192×96; we mirror that ceiling so a runaway slider can’t allocate gigabytes of index buffer.

Source

pub fn mesh_size(&self) -> (u32, u32)

Current warp mesh size as (cols, rows). Used by the GUI’s options panel to seed its widget state.

Source

pub fn update_warp_vertices(&mut self, vertices: &[WarpVertex])

Push freshly computed warp UVs to the GPU. Also caches them on the chain so the motion-vector pass can build anisotropic segments aligned with the local warp displacement.

Source

pub fn update_waveform_samples( &mut self, samples: &[f32], instantaneous_volume: f32, )

Push a fresh mono audio sample window for the waveform pass.

The renderer applies wave_smoothing (single-pole IIR) on the CPU side before upload — pass the raw samples; smoothing follows RenderState::wave.smoothing. The buffer is clamped to NUM_WAVE_SAMPLES; shorter inputs are zero-padded.

instantaneous_volume is the frame-mean abs value used by b_mod_wave_alpha_by_volume to scale the wave alpha — pass (|bass| + |mid| + |treb|) / 3 or any equivalent volume proxy in [0, 1].

Source

pub fn update_waveform_samples_lr( &mut self, left: &[f32], right: &[f32], instantaneous_volume: f32, )

Stereo variant of Self::update_waveform_samples — uploads distinct left and right channels so the waveform pass can lay them on the upper and lower screen halves when WaveParams::split_lr is true.

Source

pub fn wave_samples(&self) -> &[f32]

Borrow the current waveform sample buffer. Mostly useful for tests that want to assert the smoothing applied or the latest upload’s length.

Source

pub fn update_custom_waves( &mut self, vertices: &[CustomWaveVertex], batches: &[CustomWaveBatch], )

Upload the per-frame custom-wave vertex stream.

Source

pub fn custom_wave_vertex_count(&self) -> u32

Source

pub fn custom_wave_batch_count(&self) -> usize

Source

pub fn update_custom_shapes( &mut self, instances: &[CustomShapeInstance], batches: &[CustomShapeBatch], )

Upload the per-frame custom-shape instance stream.

Source

pub fn custom_shape_instance_count(&self) -> u32

Source

pub fn custom_shape_batch_count(&self) -> usize

Source

pub fn border_batch_count(&self) -> usize

Source

pub fn motion_vector_segment_count(&self) -> u32

Source

pub fn update_sprites(&mut self, frames: &[SpriteFrame])

Push the sprite frame list for the next Self::render call. The engine ticks its SpriteManager and feeds the resulting SpriteFrame list here. Empty slice = no sprite pass recorded next frame.

Source

pub fn sprite_frame_count(&self) -> usize

Number of sprite frames queued for the next render call. Exposed for tests + the GUI’s HUD.

Source

pub fn load_sprite_defs(&mut self, dir: &Path, def_imgs: &[String])

Reload sprite textures from a directory, in the order of the parsed MILK_IMG.INI entries. def_imgs is the parallel list of img= filenames the engine pulled from the parser. Missing files are silently substituted with a 1×1 transparent fallback; the engine’s texture_index mapping stays dense.

Source

pub fn sprite_pool(&self) -> &SpritePool

Borrow the sprite pool. Used by tests + GUI HUD.

Source

pub fn update_text_frames(&mut self, frames: &[TextFrame])

Push the text-overlay frame list for the next Self::render call. The engine ticks its MessageManager (+ optional MPRIS auto-title) and forwards the resulting TextFrame list. Empty slice = no text pass.

Source

pub fn text_frame_count(&self) -> usize

Number of text frames queued for next render.

Source

pub fn text_atlas_glyph_count(&self) -> usize

Number of glyphs currently cached in the text atlas. Test surface — grows on the first frame each glyph is requested.

Source

pub fn render(&mut self) -> Result<()>

Render a frame: record every per-chain pass (primary + optional secondary) plus the final blend, copy warp outputs into their feedback buffers, and submit. When no secondary chain is active the blend pass acts as a passthrough of the primary chain’s final_texture.

Source

pub fn start_transition(&mut self) -> Result<()>

Begin a preset transition: swap the current primary chain into the secondary slot (where it keeps fading out the outgoing preset) and allocate a fresh primary chain for the incoming preset.

The blend pass is rebound so the secondary view points at the outgoing preset (the old primary) and the primary view at the new chain. progress starts at 0 (full secondary visible) and the engine ramps it to 1 over the transition duration.

Returns Err only if the new primary chain fails to allocate (rare — a wgpu error).

Source

pub fn install_secondary_chain(&mut self, chain: RenderChain)

Install a caller-built secondary chain at the start of a preset transition. The renderer’s blend pass starts sourcing from it immediately; the caller drives set_transition_progress each frame until completion. Most callers want Self::start_transition instead — this overload exists for tests and for reclaiming a previous chain’s textures.

Source

pub fn clear_secondary_chain(&mut self) -> Option<RenderChain>

Drop the secondary chain at transition end and rebind the blend pass to passthrough of the primary chain.

Source

pub fn set_transition_progress(&self, progress: f32)

Push the current transition progress (in [0, 1]) into the blend pass uniform. 0 = full secondary (outgoing preset); 1 = full primary (incoming preset). Caller is expected to feed the eased value from the engine’s TransitionManager.

Source

pub fn secondary_chain_mut(&mut self) -> Option<&mut RenderChain>

Borrow the secondary chain mutably — used by the engine to push the outgoing preset’s warp vertices / audio samples / etc. while the transition is in flight. None outside transitions.

Source

pub fn is_transitioning(&self) -> bool

Whether a secondary chain is currently active (a transition is in flight).

Source

pub fn render_texture(&self) -> &Texture

Get the displayable texture: the final-blend pass output that composites primary + optional secondary chains. The GUI/CLI sample from this for presentation.

The name is kept for backwards compatibility with the pre-comp-pass API (the GUI’s render path imports it as engine.renderer().render_texture()); renaming would be a breaking change for consumers.

Source

pub fn warp_output_texture(&self) -> &Texture

Get the warp pass output before comp filtering. Useful for tests that want to assert on the feedback chain content directly, bypassing gamma_adj and any future display-only adjustments.

Source

pub fn read_render_texture(&self) -> Result<Vec<u8>>

Read the current final_texture back as tightly-packed RGBA8 bytes (width * height * 4). Reflects what the screen shows (post-comp), matching render_texture(). The byte order is always R, G, B, A regardless of the surface format — BGRA surfaces (the desktop default) are swizzled on the CPU before the buffer returns so callers never have to branch on format.

This is a synchronous CPU stall — intended for tests and offline snapshots, not the hot rendering path. Wgpu requires the per-row staging stride to be 256-byte aligned, so the helper copies into a padded staging buffer and unpads it before returning.

Source

pub fn state(&self) -> &RenderState

Source

pub fn update_secondary_state(&mut self, state: Option<RenderState>)

Push the outgoing preset’s RenderState for the secondary chain. Called by the engine each frame during a transition; cleared by passing None once the transition completes.

Source

pub fn update_secondary_warp_vertices(&mut self, vertices: &[WarpVertex])

Push the outgoing preset’s per-vertex warp UVs to the secondary chain. No-op when no secondary chain is active. Mirrors update_warp_vertices for the primary chain.

Source

pub fn update_secondary_waveform_samples( &mut self, samples: &[f32], instantaneous_volume: f32, wave_params: WaveParams, )

Push the outgoing preset’s audio samples to the secondary chain’s waveform pass. No-op when no secondary chain is active. The wave_params argument carries the smoothing factor for the IIR.

Source

pub fn update_secondary_waveform_samples_lr( &mut self, left: &[f32], right: &[f32], instantaneous_volume: f32, wave_params: WaveParams, )

Stereo variant of update_secondary_waveform_samples for the outgoing preset during a transition. Mirrors the primary chain’s update_waveform_samples_lr.

Source

pub fn update_secondary_custom_waves( &mut self, vertices: &[CustomWaveVertex], batches: &[CustomWaveBatch], )

Push the outgoing preset’s custom-wave vertex stream to the secondary chain. No-op when no secondary chain is active.

Source

pub fn update_secondary_custom_shapes( &mut self, instances: &[CustomShapeInstance], batches: &[CustomShapeBatch], )

Push the outgoing preset’s custom-shape instance stream to the secondary chain. No-op when no secondary chain is active.

Source

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

Resize render targets. Re-allocates per-chain textures, the blend display target, and rebinds the blend pass to the new primary view.

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
§

impl<T> Downcast<T> for T

§

fn downcast(&self) -> &T

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> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
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<T> Upcast<T> for T

§

fn upcast(&self) -> Option<&T>

§

impl<T> WasmNotSend for T
where T: Send,

§

impl<T> WasmNotSendSync for T
where T: WasmNotSend + WasmNotSync,

§

impl<T> WasmNotSync for T
where T: Sync,