V45.43: fix Ozone 11 GUI crash on Intel UHD 630 + load diagnostics

Root-cause hypothesis: fx_vst_bridge parked embed window offscreen (-20000,-20000)
during VST3 editor attach; Ozone 11 GL init null-derefs (c0000005 in
iZOzone11Core.dll+18f6b92) on Intel ICD. Reaper hosts window on-screen -> OK.

- RenderFxJob.cpp: env toggle SF_FXGUI_ATTACH_ONSCREEN=1 -> SetWindowPos(100,100)
  before fxGuiLoadAttach, park back offscreen after attach succeeds
- main_fx.cpp: FxCrashDumpHandler prints [CRASH] in <module>+0x<offset> and
  [CRASH] minidump: <path> so logs name the faulting plugin DLL directly
- app.jsx VstGuiEmbed: frameLoadedRef + 90s watchdog -> onDead if bridge alive
  but no frame (no more infinite 'Dang tai plugin VST...' flash); clearer onDead
  toasts with %TEMP%\sf_dumps\fx_bridge_crash_*.dmp hint (track + master)
- rebuild fx_vst_bridge + daw_vst_bridge, NSIS/MSI v=202609021809
This commit is contained in:
2026-09-02 21:08:49 +07:00
parent 9f3b072be0
commit 244dc8ee9e
9 changed files with 53 additions and 13 deletions
+14 -4
View File
@@ -13382,11 +13382,13 @@ const ExportProgressModal = ({ open, exportProgress, isExporting, onClose }) =>
const screenRectRef = React.useRef(null);
const [, setDead] = React.useState(false);
const [frameLoaded, setFrameLoaded] = React.useState(false);
const frameLoadedRef = React.useRef(false);
const post = (payload) => { try { fetch(url + '/input', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }).catch(() => {}); } catch (e) {} };
React.useEffect(() => {
deadRef.current = false;
setDead(false);
setFrameLoaded(false);
frameLoadedRef.current = false;
const tick = setInterval(() => {
const img = imgRef.current;
if (!img || deadRef.current) return;
@@ -13407,8 +13409,16 @@ const ExportProgressModal = ({ open, exportProgress, isExporting, onClose }) =>
// re-shows the native window at its last position, and the ~500ms
// rect refresh below re-anchors it over the panel.
try { fetch(url + '/show', { method: 'POST' }).catch(() => {}); } catch (e) {}
// Watchdog: plugin load is allowed up to 90s; if no frame arrived and
// the bridge did not die (ping alive = process stuck in plugin init/attach),
// give up so the panel does not flash "Đang tải plugin VST..." forever.
const watchdog = setTimeout(() => {
if (!deadRef.current && !frameLoadedRef.current) {
deadRef.current = true; setDead(true); onDead && onDead();
}
}, 90000);
return () => {
clearInterval(tick); clearInterval(ping); preloadRef.current = null;
clearInterval(tick); clearInterval(ping); clearTimeout(watchdog); preloadRef.current = null;
// Panel closed -> hide the native window (bridge stays alive so
// reopening is fast); POST /hide chứ không /close.
try { fetch(url + '/hide', { method: 'POST' }).catch(() => {}); } catch (e) {}
@@ -13486,7 +13496,7 @@ const ExportProgressModal = ({ open, exportProgress, isExporting, onClose }) =>
<span className="text-[11px] text-slate-500 font-mono animate-pulse">Đang tải plugin VST — GUI embed sẽ hiện khi plugin sẵn sàng...</span>
</div>
)}
<img ref={imgRef} alt="VST GUI" className="w-full h-full object-contain select-none pointer-events-none" draggable={false} onLoad={() => setFrameLoaded(true)} />
<img ref={imgRef} alt="VST GUI" className="w-full h-full object-contain select-none pointer-events-none" draggable={false} onLoad={() => { setFrameLoaded(true); frameLoadedRef.current = true; }} />
</div>
</div>
);
@@ -14019,7 +14029,7 @@ const addVst = (path) => { const fx = (fxList || []).find(f => f.path === path);
{fxGuiOpen ? (
<div className="flex-1 min-h-0">
<VstGuiEmbed url={fxGuiOpen.url} onClose={closeFxGui}
onDead={() => { window.showToast && window.showToast('Bridge VST GUI đã mất kết nối — trả về graph', 'error'); closeFxGui(); }} />
onDead={() => { window.showToast && window.showToast('Plugin VST GUI lỗi khi mở (bridge chết/treo — check %TEMP%\\sf_dumps\\fx_bridge_crash_*.dmp) — đã trả về graph', 'error'); closeFxGui(); }} />
</div>
) : (
<>
@@ -15097,7 +15107,7 @@ const addMasterVst = (path) => { const fx = (masterFxList || []).find(f => f.pat
{masterGuiOpen ? (
<div className="flex-1 flex flex-col bg-slate-950 relative min-h-0">
<VstGuiEmbed url={masterGuiOpen.url} onClose={closeMasterGui}
onDead={() => { window.showToast && window.showToast('Bridge VST GUI đã mất kết nối — trả về graph', 'error'); closeMasterGui(); }} />
onDead={() => { window.showToast && window.showToast('Plugin VST GUI lỗi khi mở (bridge chết/treo — check %TEMP%\\sf_dumps\\fx_bridge_crash_*.dmp) — đã trả về graph', 'error'); closeMasterGui(); }} />
</div>
) : (
<div className="flex-1 flex flex-col bg-slate-950 relative overflow-y-auto oz-scrollbar">
File diff suppressed because one or more lines are too long