mirror of
https://github.com/got-feedBack/feedBack-desktop.git
synced 2026-08-15 05:07:14 +00:00
Clean release snapshot
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
# GR6 fast-fail — PoC results + revised diagnosis
|
||||
|
||||
Date: 2026-05-13
|
||||
Branch: `diag/vst-trace` (unchanged) + new scratch dir `C:\Users\byron\vst-poc\` on Win11 VM
|
||||
PoC binary: `C:\Users\byron\vst-poc\build\Release\vst_poc.exe`
|
||||
|
||||
## TL;DR — the original diagnosis was half right
|
||||
|
||||
The original `DIAG-REPORT.md` proposed Fix Path 1 ("sandboxed plugin-host process with
|
||||
QApplication"). The PoC confirms **the sandboxed-process direction is correct**, but
|
||||
**QApplication is not needed at all** — the entire root cause is JUCE's message thread
|
||||
not being the OS main thread.
|
||||
|
||||
| Mode | Process | JUCE MessageManager thread | QApplication? | GR6 editor opens? |
|
||||
|---|---|---|---|---|
|
||||
| Baseline | `node load-gr6.js` | JUCE-internal (TID ≠ main) | no | **crashes** in 1–2 s with `0xC0000409` |
|
||||
| PoC #1 | `vst_poc.exe` | OS main thread (TID == main) | yes (Qt 5.15.2) | **clean**, editor 1110×780, runs 10 s, exit 0 |
|
||||
| PoC #2 | `vst_poc.exe POC_NO_QAPP=1` | OS main thread (TID == main) | **no** | **clean**, editor 1110×780, runs 10 s, exit 0 |
|
||||
|
||||
PoC #2 is the load-bearing experiment: dropping QApplication entirely still works as long
|
||||
as JUCE owns the OS main thread. The "no QCoreApplication instance" Qt warnings the
|
||||
original report flagged don't even fire in PoC #2 — GR6's static-linked Qt5 is happy as
|
||||
long as the calling thread has the OS-main-thread properties it expects.
|
||||
|
||||
## How the PoC reproduces / refutes the bug
|
||||
|
||||
```cpp
|
||||
// main.cpp (essentials)
|
||||
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
|
||||
// OPTIONAL — POC_NO_QAPP env disables this leg. Same outcome either way.
|
||||
QApplication qapp(qArgc, qArgv);
|
||||
|
||||
juce::ScopedJuceInitialiser_GUI juceInit; // (a) MessageManager bound to TID=WinMain
|
||||
VSTHost host;
|
||||
auto plugin = host.loadPlugin(GR6_PATH, 48000.0, 256, err);
|
||||
auto editor = plugin->createEditor(); // (b) runs on the same TID
|
||||
editor->setSize(1000, 600);
|
||||
EditorWindow window(...); window.setVisible(true);
|
||||
|
||||
while (alive) { // (c) message pump on main thread
|
||||
juce::MessageManager::getInstance()->runDispatchLoopUntil(50);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The three pieces above are necessary and sufficient. Compare to today's Slopsmith addon:
|
||||
|
||||
```cpp
|
||||
// src/audio/NodeAddon.cpp::OpenPluginEditor
|
||||
juce::MessageManager::callAsync([processor, ...]() {
|
||||
auto* editor = processor->createEditor(); // runs on JUCE's worker thread,
|
||||
... // which is NOT the V8/main thread
|
||||
});
|
||||
```
|
||||
|
||||
Inside a Node native addon, V8 owns the OS main thread; JUCE silently spins up its own
|
||||
"message thread" via `MessageManager::startup()` to give itself a place to run UI work.
|
||||
That thread has a Win32 message queue but it is not a `QThread` and is not the OS main
|
||||
thread. GR6's embedded Qt5 starts timers and connects QML signals on whatever thread
|
||||
created its editor, hits Qt's thread-affinity guards (`Timers can only be used with
|
||||
threads started with QThread`, `Illegal attempt to connect ... different thread than the
|
||||
QML engine`), then `__fastfail`s.
|
||||
|
||||
## Revised recommended fix
|
||||
|
||||
`slopsmith-vst-host.exe` — a sandbox-process plugin host. **Same shape as the PoC,
|
||||
without the Qt link.** Concretely:
|
||||
|
||||
1. **Subprocess binary**: standalone Win32 exe with `WinMain`. Loads exactly one VST3 via
|
||||
the existing JUCE `VSTHost`. Runs JUCE's MessageManager on its main thread, opens the
|
||||
editor on its main thread, owns the editor HWND.
|
||||
2. **No QApplication, no Qt link**: PoC #2 proves it isn't needed for GR6. Drop the
|
||||
~50 MB of Qt deps the original report assumed.
|
||||
3. **IPC for audio + control**: shared-memory ring buffer for audio, named pipe for
|
||||
control messages (load, setParameter, openEditor, etc.). Same surface as the current
|
||||
in-process `VSTHost`, so `SignalChain` doesn't have to know.
|
||||
4. **Detection**: only route through the sandbox for plugins that fail in-process.
|
||||
The PoC plus the Qt warnings in the JUCE-thread case strongly suggest any Qt-using
|
||||
plugin (Reaktor 6, Massive X, Komplete Kontrol, Battery 4, etc.) has the same issue;
|
||||
non-Qt plugins (most JUCE-based ones) are fine in-process.
|
||||
|
||||
## What is dropped vs. the original plan
|
||||
|
||||
- **Qt dependency entirely.** ~2 weeks of "make Qt cohabit with JUCE" work doesn't happen
|
||||
because we don't need Qt.
|
||||
- The "Qt main loop must own the message pump" anxiety in the original §"Why fixing this
|
||||
in-process is hard" doesn't apply — Win32 message pump (drained by JUCE's
|
||||
`runDispatchLoopUntil`) is enough.
|
||||
- The original cost estimate of ~2 weeks for single-plugin sandbox / ~1 month for pooled
|
||||
is still roughly right, dominated by the IPC layer, not Qt.
|
||||
|
||||
## Followups
|
||||
|
||||
- **Editor window reparenting**: the production sandbox needs to reparent the plugin's
|
||||
HWND into the Electron renderer (or pop a separate top-level window owned by Electron).
|
||||
Standard pattern — `SetParent` from the sandbox after sending the HWND over IPC.
|
||||
- **Audio latency budget**: one extra IPC hop adds ~1–2 ms at 48 kHz/256 frames. Fine
|
||||
for guitar processing; reconsider for low-latency monitoring. Use a shared-memory ring
|
||||
+ futex-style signalling (Windows events) to avoid syscall round-trips per buffer.
|
||||
- **Crash isolation**: a plugin in the sandbox crashing only takes down its own process;
|
||||
Slopsmith Desktop can detect, log, restart. Bigger win than just fixing GR6.
|
||||
|
||||
## Reproducing the baseline crash
|
||||
|
||||
The in-process load that motivated this work is reproduced via the
|
||||
existing smoke harness on a Windows host with GR6 installed:
|
||||
|
||||
```bat
|
||||
cd <slopsmith-desktop checkout>
|
||||
node scripts\dev\load-gr6.js
|
||||
```
|
||||
|
||||
Before this PR's sandbox patch, that command crashed with
|
||||
`STATUS_STACK_BUFFER_OVERRUN (0xC0000409)` from the Qt5 GR6 path. The
|
||||
single-file PoC that confirmed the QApplication-on-message-thread fix
|
||||
lived under a developer-local scratch tree during investigation; the
|
||||
findings are summarised above and the production fix is the
|
||||
out-of-process sandbox in this PR. There is no reproducible artefact to
|
||||
ship for the PoC — the experiment is fully captured by the diagnostic
|
||||
narrative above.
|
||||
Reference in New Issue
Block a user