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: RenderChainPrimary 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: FinalBlendPipelineFinal 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: RenderStatePrimary 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: ShaderCompilerCaches 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: TexturePoolUser 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: SpritePipelineSprite 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: SpritePoolSprite 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: TextPipelineText 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
impl MilkRenderer
Sourcepub async fn new(config: RenderConfig) -> Result<Self>
pub async fn new(config: RenderConfig) -> Result<Self>
Create a new renderer that owns its GPU device.
Sourcepub fn from_gpu_context(gpu: GpuContext) -> Result<Self>
pub fn from_gpu_context(gpu: GpuContext) -> Result<Self>
Create a renderer atop a shared GPU context.
Sourcepub fn set_texture_pool(&mut self, pool: TexturePool)
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.
Sourcepub fn texture_pool(&self) -> &TexturePool
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.
Sourcepub fn gpu_device(&self) -> Arc<Device>
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.
Sourcepub fn gpu_queue(&self) -> Arc<Queue>
pub fn gpu_queue(&self) -> Arc<Queue>
Borrow the underlying GPU queue. Mirror of gpu_device for the
pool-construction path.
Sourcepub fn render_format(&self) -> TextureFormat
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.
Sourcepub fn render_size(&self) -> (u32, u32)
pub fn render_size(&self) -> (u32, u32)
Render-target width × height in pixels. Mirrors RenderConfig.
Sourcepub fn set_user_comp_shader(&mut self, hlsl: Option<&str>) -> Result<bool>
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.
Sourcepub fn set_user_comp_shader_for_preset(
&mut self,
hlsl: Option<&str>,
preset_id: &str,
) -> Result<bool>
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.
Sourcefn build_texture_plan(
&self,
refs: &[UserSamplerRef],
preset_id: &str,
) -> (TextureBindingPlan, [Option<TextureView>; 8])
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.
Sourcefn resolve_logical_texture(
&self,
logical: &str,
preset_id: &str,
) -> Option<Arc<UserTexture>>
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.
Sourcepub fn has_user_comp_shader(&self) -> bool
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.
Sourcepub fn set_user_warp_shader(&mut self, hlsl: Option<&str>) -> Result<bool>
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.
Sourcepub fn set_user_warp_shader_for_preset(
&mut self,
hlsl: Option<&str>,
preset_id: &str,
) -> Result<bool>
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).
Sourcepub fn has_user_warp_shader(&self) -> bool
pub fn has_user_warp_shader(&self) -> bool
Whether the warp pass is currently driven by a user-authored shader.
Sourcepub fn update_state(&mut self, state: RenderState)
pub fn update_state(&mut self, state: RenderState)
Update render state.
Sourcepub fn set_mesh_size(&mut self, cols: u32, rows: u32)
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.
Sourcepub fn mesh_size(&self) -> (u32, u32)
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.
Sourcepub fn update_warp_vertices(&mut self, vertices: &[WarpVertex])
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.
Sourcepub fn update_waveform_samples(
&mut self,
samples: &[f32],
instantaneous_volume: f32,
)
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].
Sourcepub fn update_waveform_samples_lr(
&mut self,
left: &[f32],
right: &[f32],
instantaneous_volume: f32,
)
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.
Sourcepub fn wave_samples(&self) -> &[f32]
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.
Sourcepub fn update_custom_waves(
&mut self,
vertices: &[CustomWaveVertex],
batches: &[CustomWaveBatch],
)
pub fn update_custom_waves( &mut self, vertices: &[CustomWaveVertex], batches: &[CustomWaveBatch], )
Upload the per-frame custom-wave vertex stream.
pub fn custom_wave_vertex_count(&self) -> u32
pub fn custom_wave_batch_count(&self) -> usize
Sourcepub fn update_custom_shapes(
&mut self,
instances: &[CustomShapeInstance],
batches: &[CustomShapeBatch],
)
pub fn update_custom_shapes( &mut self, instances: &[CustomShapeInstance], batches: &[CustomShapeBatch], )
Upload the per-frame custom-shape instance stream.
pub fn custom_shape_instance_count(&self) -> u32
pub fn custom_shape_batch_count(&self) -> usize
pub fn border_batch_count(&self) -> usize
pub fn motion_vector_segment_count(&self) -> u32
Sourcepub fn update_sprites(&mut self, frames: &[SpriteFrame])
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.
Sourcepub fn sprite_frame_count(&self) -> usize
pub fn sprite_frame_count(&self) -> usize
Number of sprite frames queued for the next render call. Exposed for tests + the GUI’s HUD.
Sourcepub fn load_sprite_defs(&mut self, dir: &Path, def_imgs: &[String])
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.
Sourcepub fn sprite_pool(&self) -> &SpritePool
pub fn sprite_pool(&self) -> &SpritePool
Borrow the sprite pool. Used by tests + GUI HUD.
Sourcepub fn update_text_frames(&mut self, frames: &[TextFrame])
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.
Sourcepub fn text_frame_count(&self) -> usize
pub fn text_frame_count(&self) -> usize
Number of text frames queued for next render.
Sourcepub fn text_atlas_glyph_count(&self) -> usize
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.
Sourcepub fn render(&mut self) -> Result<()>
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.
Sourcepub fn start_transition(&mut self) -> Result<()>
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).
Sourcepub fn install_secondary_chain(&mut self, chain: RenderChain)
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.
Sourcepub fn clear_secondary_chain(&mut self) -> Option<RenderChain>
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.
Sourcepub fn set_transition_progress(&self, progress: f32)
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.
Sourcepub fn secondary_chain_mut(&mut self) -> Option<&mut RenderChain>
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.
Sourcepub fn is_transitioning(&self) -> bool
pub fn is_transitioning(&self) -> bool
Whether a secondary chain is currently active (a transition is in flight).
Sourcepub fn render_texture(&self) -> &Texture
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.
Sourcepub fn warp_output_texture(&self) -> &Texture
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.
Sourcepub fn read_render_texture(&self) -> Result<Vec<u8>>
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.
pub fn state(&self) -> &RenderState
Sourcepub fn update_secondary_state(&mut self, state: Option<RenderState>)
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.
Sourcepub fn update_secondary_warp_vertices(&mut self, vertices: &[WarpVertex])
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.
Sourcepub fn update_secondary_waveform_samples(
&mut self,
samples: &[f32],
instantaneous_volume: f32,
wave_params: WaveParams,
)
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.
Sourcepub fn update_secondary_waveform_samples_lr(
&mut self,
left: &[f32],
right: &[f32],
instantaneous_volume: f32,
wave_params: WaveParams,
)
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.
Sourcepub fn update_secondary_custom_waves(
&mut self,
vertices: &[CustomWaveVertex],
batches: &[CustomWaveBatch],
)
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.
Sourcepub fn update_secondary_custom_shapes(
&mut self,
instances: &[CustomShapeInstance],
batches: &[CustomShapeBatch],
)
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.
Auto Trait Implementations§
impl Freeze for MilkRenderer
impl !RefUnwindSafe for MilkRenderer
impl Send for MilkRenderer
impl Sync for MilkRenderer
impl Unpin for MilkRenderer
impl !UnwindSafe for MilkRenderer
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
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