From b38f2720134e36c56ddefbcdf261f3364dcf226f Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Sun, 20 Dec 2020 12:29:59 +0100 Subject: [PATCH] Run all other lifecycle events on main thread This is probably where plugins instantiate timers for their GUI updates. --- src/wine-host/bridges/vst3.cpp | 66 +++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 20 deletions(-) diff --git a/src/wine-host/bridges/vst3.cpp b/src/wine-host/bridges/vst3.cpp index c6e93056..8f110fc1 100644 --- a/src/wine-host/bridges/vst3.cpp +++ b/src/wine-host/bridges/vst3.cpp @@ -86,20 +86,35 @@ void Vst3Bridge::run() { // Even though we're requesting a specific interface (to mimic // what the host is doing), we're immediately upcasting it to an // `FUnknown` so we can create a perfect proxy object. - Steinberg::IPtr object; - switch (request.requested_interface) { - case Vst3PluginProxy::Construct::Interface::IComponent: - object = - module->getFactory() - .createInstance( - cid); - break; - case Vst3PluginProxy::Construct::Interface::IEditController: - object = module->getFactory() - .createInstance< - Steinberg::Vst::IEditController>(cid); - break; - } + // We create the object from the GUI thread in case it + // immediatly starts timers or something (even though it + // shouldn't) + Steinberg::IPtr object = + main_context + .run_in_context>( + [&]() -> Steinberg::IPtr { + switch (request.requested_interface) { + case Vst3PluginProxy::Construct::Interface:: + IComponent: + return module->getFactory() + .createInstance< + Steinberg::Vst::IComponent>( + cid); + break; + case Vst3PluginProxy::Construct::Interface:: + IEditController: + return module->getFactory() + .createInstance< + Steinberg::Vst:: + IEditController>(cid); + break; + default: + // Unreachable + return nullptr; + break; + } + }) + .get(); if (object) { std::lock_guard lock(object_instances_mutex); @@ -490,15 +505,26 @@ void Vst3Bridge::run() { nullptr; } - return object_instances[request.instance_id] - .plugin_base->initialize( - object_instances[request.instance_id] - .host_context_proxy); + // XXX: Should `IPlugView::{initialize,terminate}` be run from + // the main UI thread? I can see how plugins would want to + // start timers from here. + return main_context + .run_in_context([&]() { + return object_instances[request.instance_id] + .plugin_base->initialize( + object_instances[request.instance_id] + .host_context_proxy); + }) + .get(); }, [&](const YaPluginBase::Terminate& request) -> YaPluginBase::Terminate::Response { - return object_instances[request.instance_id] - .plugin_base->terminate(); + return main_context + .run_in_context([&]() { + return object_instances[request.instance_id] + .plugin_base->terminate(); + }) + .get(); }, [&](const YaPluginFactory::Construct&) -> YaPluginFactory::Construct::Response {