From 1739959f2649a283e4604c740aa8542cd8aa5a0e Mon Sep 17 00:00:00 2001 From: OpenSauce Date: Mon, 27 Jul 2026 14:53:03 +0100 Subject: [PATCH 1/4] fix(plugin): stop the editor aborting the host on Windows Loading the VST3 in REAPER on Windows killed the DAW the moment the editor opened, with exception 0xc0000409 and Rustortion.vst3 as the faulting module. That code is `__fastfail(FATAL_APP_EXIT)` -- Rust's `abort()`. nih-plug's log had the cause: panicked at 'called `Option::unwrap()` on a `None` value': iced_baseview/src/conversion.rs:781 The Win32 arm of `convert_raw_window_handle` tested `hinstance.is_null()` and then unwrapped `NonZeroIsize::new(hinstance)` inside the `.then()` closure -- which runs precisely when the pointer *is* null. baseview fills in only `hwnd` and leaves `hinstance` null on every window, so this fired on every editor open; the panic crossed the extern "C" wrapper boundary, became a non-unwinding panic, and aborted the host. Linux takes the Xlib arm, which is why neither CI nor local dev ever saw it. Fixed upstream in the fork (OpenSauce/iced_baseview@f76ba2f1), which recovers the HINSTANCE from the window via `GetWindowLongPtrW(GWLP_HINSTANCE)` rather than passing the null through -- wgpu's Vulkan backend refuses a surface without one. Co-Authored-By: Claude Opus 5 (1M context) --- Cargo.lock | 3 ++- rustortion-plugin/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8d96739..08d1f2e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1934,7 +1934,7 @@ dependencies = [ [[package]] name = "iced_baseview" version = "0.1.0" -source = "git+https://github.com/OpenSauce/iced_baseview.git?rev=2377031b#2377031b0fbea47356d673996aabc2c0146b3dd2" +source = "git+https://github.com/OpenSauce/iced_baseview.git?rev=f76ba2f1#f76ba2f1ec3affc643528a79aa7a178b33a7cd13" dependencies = [ "baseview", "cfg-if", @@ -1949,6 +1949,7 @@ dependencies = [ "raw-window-handle 0.6.2", "thiserror 1.0.69", "window_clipboard 0.4.1", + "windows-sys 0.61.2", ] [[package]] diff --git a/rustortion-plugin/Cargo.toml b/rustortion-plugin/Cargo.toml index 9bdc218..713cbd7 100644 --- a/rustortion-plugin/Cargo.toml +++ b/rustortion-plugin/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["cdylib"] rustortion-core = { path = "../rustortion-core" } nih_plug = { git = "https://github.com/robbert-vdh/nih-plug.git", rev = "28b149ec" } rustortion-ui = { path = "../rustortion-ui" } -iced_baseview = { git = "https://github.com/OpenSauce/iced_baseview.git", rev = "2377031b" } +iced_baseview = { git = "https://github.com/OpenSauce/iced_baseview.git", rev = "f76ba2f1" } crossbeam = "0.8" log = "0.4" dirs = "6" From b0b4b5d269140c26653e3deeb288c9856d02a9a4 Mon Sep 17 00:00:00 2001 From: OpenSauce Date: Mon, 27 Jul 2026 15:10:28 +0100 Subject: [PATCH 2/4] fix(plugin): redraw the editor continuously to stop it flickering With the Windows abort out of the way the editor renders, but flickers while it is open. `IcedBaseviewSettings::default()` leaves `always_redraw` off, so iced redraws only when it decides it has something new to show. baseview cannot request a redraw when the window's visibility changes, so between the two the window can end up presenting a swapchain buffer that nothing ever drew into -- stale on Windows, blank on a reopened editor. Upstream's own doc comment describes the default as the thing to work around, and `nih_plug_iced` hard-codes the opposite (`nih_plug_iced/src/editor.rs:104`). Cost is a redraw per baseview window update while the editor is open, which is what every other iced-based plugin editor already pays. Co-Authored-By: Claude Opus 5 (1M context) --- rustortion-plugin/src/editor.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/rustortion-plugin/src/editor.rs b/rustortion-plugin/src/editor.rs index 6464126..74c5f53 100644 --- a/rustortion-plugin/src/editor.rs +++ b/rustortion-plugin/src/editor.rs @@ -84,7 +84,18 @@ impl Editor for PluginEditor { scale: iced_baseview::baseview::WindowScalePolicy::SystemScaleFactor, }, graphics_settings: iced_baseview::graphics::Settings::default(), - iced_baseview: iced_baseview::settings::IcedBaseviewSettings::default(), + iced_baseview: iced_baseview::settings::IcedBaseviewSettings { + ignore_non_modifier_keys: false, + // Not a performance knob — a correctness one. iced redraws only + // when it has a reason to, and baseview cannot ask for one when + // the window changes visibility, so the window is left + // presenting a swapchain buffer nothing ever drew into. On + // Windows that reads as the editor flickering; it is also why a + // reopened editor can come up blank. `nih_plug_iced` sets this + // for the same reason, and the default of `false` is what the + // upstream doc comment calls a workaround target. + always_redraw: true, + }, ..Default::default() }; From 0e62925419e67fc50ba1164fe7667738bd0d10b9 Mon Sep 17 00:00:00 2001 From: OpenSauce Date: Mon, 27 Jul 2026 15:29:33 +0100 Subject: [PATCH 3/4] Revert "fix(plugin): redraw the editor continuously to stop it flickering" This reverts commit b0b4b5d269140c26653e3deeb288c9856d02a9a4. It did not fix the flicker, and it broke the dropdowns: `always_redraw` forces `needs_update` true on every frame (iced_baseview application.rs:424), which tears down and rebuilds the whole `UserInterface` continuously -- and a `pick_list` dropdown is an overlay that has to survive across frames to stay open and take a click. The flicker turned out to follow the graphics backend, not the redraw rate: forcing `WGPU_BACKEND=gl` removes it while the default DX12 path shows it. Co-Authored-By: Claude Opus 5 (1M context) --- rustortion-plugin/src/editor.rs | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/rustortion-plugin/src/editor.rs b/rustortion-plugin/src/editor.rs index 74c5f53..6464126 100644 --- a/rustortion-plugin/src/editor.rs +++ b/rustortion-plugin/src/editor.rs @@ -84,18 +84,7 @@ impl Editor for PluginEditor { scale: iced_baseview::baseview::WindowScalePolicy::SystemScaleFactor, }, graphics_settings: iced_baseview::graphics::Settings::default(), - iced_baseview: iced_baseview::settings::IcedBaseviewSettings { - ignore_non_modifier_keys: false, - // Not a performance knob — a correctness one. iced redraws only - // when it has a reason to, and baseview cannot ask for one when - // the window changes visibility, so the window is left - // presenting a swapchain buffer nothing ever drew into. On - // Windows that reads as the editor flickering; it is also why a - // reopened editor can come up blank. `nih_plug_iced` sets this - // for the same reason, and the default of `false` is what the - // upstream doc comment calls a workaround target. - always_redraw: true, - }, + iced_baseview: iced_baseview::settings::IcedBaseviewSettings::default(), ..Default::default() }; From ad1df4acf3a8b0573b2cd8941a27561c74c9baaf Mon Sep 17 00:00:00 2001 From: OpenSauce Date: Mon, 27 Jul 2026 20:26:37 +0100 Subject: [PATCH 4/4] build(plugin): pin iced_baseview to the fork's v0.1.0 tag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dep pointed at a bare `rev` on a topic branch (`f76ba2f1`, on `fix/win32-hinstance`), which is not a released state and says nothing about what it contains. The fork now has a `v0.1.0` tag containing that fix — PR #1 merged, plus a metadata commit — so pin to the tag instead. Resolves to a0c8040d, verified to contain f76ba2f1. CLAUDE.md called this an "unpinned git dep", which was already wrong and is now doubly so; corrected to name the tag and say that moving it means cutting a release on the fork first. --- CLAUDE.md | 3 ++- Cargo.lock | 14 +++++++------- rustortion-plugin/Cargo.toml | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 0add1c8..750db80 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -86,7 +86,8 @@ Nothing to add in `rustortion-plugin/src/params.rs` — stage parameters are not - **IR files** live in `impulse_responses/` and `~/.config/rustortion/impulse_responses/`; loading is async, off the RT thread. Keep convolver type configurable — FIR beat FFT on the Pi in real testing, and the TwoStage tail math is numerically wrong until REV-2 lands. -- **iced_baseview** is a fork at `github.com/OpenSauce/iced_baseview` (unpinned git dep). +- **iced_baseview** is a fork at `github.com/OpenSauce/iced_baseview`, pinned to tag `v0.1.0`. + Moving it means tagging a release on the fork first — don't repoint it at a bare `rev`. - **The plugin exposes 9 global params only** (`params.rs`, ~117 lines): output level, IR gain/bypass, pitch shift, HP/LP enable+cutoff, preset index. The nested per-slot param arrays were deleted in REV-4 — they were never read by `process()`. Stage settings travel through `chain_state` (preset diff --git a/Cargo.lock b/Cargo.lock index 08d1f2e..afce05f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1224,7 +1224,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -1251,7 +1251,7 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab8ecd87370524b461f8557c119c405552c396ed91fc0a8eec68679eab26f94a" dependencies = [ - "libloading 0.8.9", + "libloading 0.7.4", ] [[package]] @@ -1356,7 +1356,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -1934,7 +1934,7 @@ dependencies = [ [[package]] name = "iced_baseview" version = "0.1.0" -source = "git+https://github.com/OpenSauce/iced_baseview.git?rev=f76ba2f1#f76ba2f1ec3affc643528a79aa7a178b33a7cd13" +source = "git+https://github.com/OpenSauce/iced_baseview.git?tag=v0.1.0#a0c8040d48ad01eb5a76a53de35de15e33f1de6b" dependencies = [ "baseview", "cfg-if", @@ -3796,7 +3796,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.12.1", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -4304,7 +4304,7 @@ dependencies = [ "getrandom 0.4.2", "once_cell", "rustix 1.1.4", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -5192,7 +5192,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] diff --git a/rustortion-plugin/Cargo.toml b/rustortion-plugin/Cargo.toml index 713cbd7..9467df9 100644 --- a/rustortion-plugin/Cargo.toml +++ b/rustortion-plugin/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["cdylib"] rustortion-core = { path = "../rustortion-core" } nih_plug = { git = "https://github.com/robbert-vdh/nih-plug.git", rev = "28b149ec" } rustortion-ui = { path = "../rustortion-ui" } -iced_baseview = { git = "https://github.com/OpenSauce/iced_baseview.git", rev = "f76ba2f1" } +iced_baseview = { git = "https://github.com/OpenSauce/iced_baseview.git", tag = "v0.1.0" } crossbeam = "0.8" log = "0.4" dirs = "6"