df4a22b9b4
JuceFxGuiHost: GUI thread rieng chay juce MessageManager runDispatchLoopUntil(10) + tick 30ms inline cadence (JUCE Timer KHONG fire tren GUI thread rieng — da xac minh selftest), PluginWindow (DocumentWindow native 'FX slot N') attach editor, reconcile dong editor+ window, teardown thu tu. runOnGui(): plugin instance phai tao tren GUI thread — JUCE plugin gan MM vao thread tao instance, editor tao thread khac -> treo (M1 chi chay vi main thread vua tao instance vua la message thread); prepare/shutdown bao qua runOnGui. JuceFxLoop: guiHost.start() TRUOC engine.prepare; re-prepare sau waitEditorsClosed(1500); teardown runOnGui(shutdown) truoc stop(). Idle ~0 CPU (khong feeder, khong instance 2). juce_fx_gui_selftest (khong ship) PASS tren purecomp + fast-compressor: open/hide/show/ resize/close, teardown sach; window native chup duoc (PrintWindow). Regression M1 selftest OK.
72 lines
3.2 KiB
C++
72 lines
3.2 KiB
C++
// native_bridge/juce_fx/JuceFxGuiHost.h
|
|
// M2: GUI thread + window host (Reaper-style) — host editor của ĐÚNG instance
|
|
// DSP trong graph ngay trong fxrt_bridge (juce_fx_bridge.exe), không instance
|
|
// 2 / feeder (nguyên nhân CPU 100% .24).
|
|
//
|
|
// GUI thread riêng (BELOW_NORMAL) chạy juce::MessageManager + tick 30ms:
|
|
// engine.pumpEditorQueue() → reconcile window theo editor state.
|
|
// PluginWindow (DocumentWindow native) bọc juce::AudioProcessorEditor mà
|
|
// ENGINE sở hữu — window KHÔNG sở hữu content (setContentNonOwned).
|
|
// Idle (không Open, không play) ≈ 0 CPU như Reaper.
|
|
#pragma once
|
|
#include <atomic>
|
|
#include <cstdint>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <thread>
|
|
|
|
class JuceFxEngine;
|
|
|
|
class JuceFxGuiHost {
|
|
public:
|
|
explicit JuceFxGuiHost(JuceFxEngine& engine);
|
|
~JuceFxGuiHost(); // .cpp (Impl incomplete ở header)
|
|
JuceFxGuiHost(const JuceFxGuiHost&) = delete;
|
|
JuceFxGuiHost& operator=(const JuceFxGuiHost&) = delete;
|
|
|
|
// Start GUI thread (thread này thành JUCE message thread). Gọi TRƯỚC mọi
|
|
// engine.prepare() — plugin instance phải tạo trên GUI thread (plugin JUCE
|
|
// MM gắn thread tạo instance; editor tạo thread khác → treo — M1 chỉ chạy
|
|
// vì main thread vừa tạo instance vừa là message thread).
|
|
void start();
|
|
// Chạy task đồng bộ trên GUI thread (chờ xong). Main/audio thread dùng để
|
|
// bọc engine.prepare()/shutdown() — instance + editor sống trên cùng thread
|
|
// như plugin yêu cầu. KHÔNG gọi từ GUI thread; không started → chạy inline.
|
|
template <typename F>
|
|
void runOnGui(F&& f) {
|
|
enqueueGuiTask([f = std::forward<F>(f)]() mutable { f(); });
|
|
}
|
|
// Đóng editor + dừng GUI thread + join (tối đa 2s, detach nếu GUI thread
|
|
// kẹt trong plugin editor). Gọi TRƯỚC engine.shutdown().
|
|
void stop();
|
|
// Main thread: enqueue Close cho mọi editor đang mở + chờ GUI thread pump
|
|
// xong (poll hasOpenEditor). Bắt buộc trước engine.prepare()/shutdown()
|
|
// khi GUI thread đang chạy (editor là JUCE Component — xoá trên message
|
|
// thread). Không started → return ngay.
|
|
void waitEditorsClosed(uint32_t timeoutMs);
|
|
// Thread-safe: số host window đang tồn tại (selftest).
|
|
uint32_t windowCount() const { return winCount_.load(); }
|
|
// GUI thread: X button của PluginWindow slot → engine Close (queue) — tick
|
|
// sau pump + reconcile xoá window.
|
|
void onWindowClose(uint32_t slot);
|
|
// GUI thread tick 30ms (GuiTickTimer trong .cpp gọi): pump + reconcile.
|
|
void tick();
|
|
|
|
private:
|
|
// runOnGui: xếp task cho GUI thread + chờ hoàn thành (count-based).
|
|
void enqueueGuiTask(std::function<void()> task);
|
|
// GUI thread: tạo/xoá/ẩn-hiện PluginWindow theo engine editor state.
|
|
void reconcile();
|
|
// GUI thread entry.
|
|
void guiMain();
|
|
|
|
struct Impl;
|
|
std::unique_ptr<Impl> impl_; // windows_ (PluginWindow chỉ thấy trong .cpp)
|
|
JuceFxEngine& engine_;
|
|
std::thread thread_;
|
|
std::atomic<bool> started_{false};
|
|
std::atomic<bool> quit_{false};
|
|
std::atomic<bool> guiExited_{false};
|
|
std::atomic<uint32_t> winCount_{0};
|
|
};
|