Also handle mutual recursion in *::getState()

VST3 plugins could freeze in REAPER when the plugin sends
`IComponentHandler::performEdit()` followed by
`IPlugFrame::resizeView()` when REAPER simultaneously tries to call
`*::getState()`. Here `*::getState()` gets called from the GUI thread,
while `IPlugFrame::resizeView()` has to be handled on REAPER's GUI
thread, resulting in a deadlock unless we use the plugin-side mutual
recursion mechanism.

I've seen this cause issues with PSPaudioware InfiniStrip.
This commit is contained in:
Robbert van der Helm
2021-05-02 16:34:32 +02:00
parent a83ff5a36a
commit 62efc1c273
3 changed files with 47 additions and 21 deletions
@@ -442,6 +442,40 @@ class Vst3PluginProxyImpl : public Vst3PluginProxy {
*/
void clear_parameter_cache();
/**
* If we have an active `IPlugView` instance, try to use the mutual
* recursion mechanism so that callbacks made by the plugin can be handled
* on this same thread. In case this is an audio processor with a separate
* edit controller, we'll also check if the object we're connected to has an
* active `IPlugView` instance. When there's no active `IPlugView` instance,
* we'll just send the event message like normal. This is needed to be able
* to handle function calls made by the host (which is mostly relevant for
* REAPER) on the GUI thread, when the plugin makes a callback to the host
* that should also be handled on that same thread (context menus and
* plugin-driven resizes).
*/
template <typename T>
typename T::Response maybe_send_mutually_recursive_message(
const T& object) {
if (last_created_plug_view_active) {
return last_created_plug_view->send_mutually_recursive_message(
std::move(object));
} else if (connected_instance_id) {
// We should also be able to handle the above situation when a
// `setState()` on a processor triggers a resize coming from the
// edit controller. To do that, we'll also check if the connected
// instance has an active plug view.
Vst3PluginProxyImpl& other_instance =
bridge.plugin_proxies.at(*connected_instance_id).get();
if (other_instance.last_created_plug_view_active) {
return other_instance.last_created_plug_view
->send_mutually_recursive_message(std::move(object));
}
}
return bridge.send_message(std::move(object));
}
Vst3PluginBridge& bridge;
/**