diff --git a/src/common/logging/clap.cpp b/src/common/logging/clap.cpp index 038a399b..5ed8c96e 100644 --- a/src/common/logging/clap.cpp +++ b/src/common/logging/clap.cpp @@ -38,16 +38,22 @@ bool ClapLogger::log_request(bool is_host_plugin, }); } +bool ClapLogger::log_request(bool is_host_plugin, + const clap::plugin::Destroy& request) { + return log_request_base(is_host_plugin, [&](auto& message) { + message << request.instance_id << ": clap_plugin::destroy()"; + }); +} + bool ClapLogger::log_request(bool is_host_plugin, const WantsConfiguration&) { return log_request_base(is_host_plugin, [&](auto& message) { message << "Requesting "; }); } -// void ClapLogger::log_response(bool is_host_plugin, const Ack&) { -// log_response_base(is_host_plugin, [&](auto& message) { message << "ACK"; -// }); -// } +void ClapLogger::log_response(bool is_host_plugin, const Ack&) { + log_response_base(is_host_plugin, [&](auto& message) { message << "ACK"; }); +} void ClapLogger::log_response( bool is_host_plugin, diff --git a/src/common/logging/clap.h b/src/common/logging/clap.h index e81979d8..b0186040 100644 --- a/src/common/logging/clap.h +++ b/src/common/logging/clap.h @@ -47,6 +47,7 @@ class ClapLogger { bool log_request(bool is_host_plugin, const clap::plugin_factory::List&); bool log_request(bool is_host_plugin, const clap::plugin_factory::Create&); + bool log_request(bool is_host_plugin, const clap::plugin::Destroy&); // TODO: Audio thread requests // bool log_request(bool is_host_plugin, @@ -54,7 +55,7 @@ class ClapLogger { bool log_request(bool is_host_plugin, const WantsConfiguration&); - // void log_response(bool is_host_plugin, const Ack&); + void log_response(bool is_host_plugin, const Ack&); void log_response(bool is_host_plugin, const clap::plugin_factory::ListResponse&); void log_response(bool is_host_plugin, diff --git a/src/common/serialization/clap.h b/src/common/serialization/clap.h index 7c0cb98b..be75d6dc 100644 --- a/src/common/serialization/clap.h +++ b/src/common/serialization/clap.h @@ -41,7 +41,8 @@ // serialize this without it. using ClapMainThreadControlRequest = std::variant; + clap::plugin_factory::Create, + clap::plugin::Destroy>; template void serialize(S& s, ClapMainThreadControlRequest& payload) { diff --git a/src/common/serialization/clap/plugin.h b/src/common/serialization/clap/plugin.h index a2b247a7..4083f307 100644 --- a/src/common/serialization/clap/plugin.h +++ b/src/common/serialization/clap/plugin.h @@ -24,6 +24,7 @@ #include #include "../../bitsery/ext/in-place-optional.h" +#include "../common.h" // Serialization messages for `clap/plugin.h` @@ -104,6 +105,22 @@ struct Descriptor { mutable clap_plugin_descriptor_t clap_descriptor; }; +/** + * Message struct for `clap_plugin::destroy()`. The Wine plugin host should + * clean up the plugin, and everything is also cleaned up on the plugin side + * after receiving acknowledgement + */ +struct Destroy { + using Response = Ack; + + native_size_t instance_id; + + template + void serialize(S& s) { + s.value8b(instance_id); + } +}; + } // namespace plugin } // namespace clap diff --git a/src/plugin/bridges/clap-impls/plugin-proxy.cpp b/src/plugin/bridges/clap-impls/plugin-proxy.cpp index 0d733978..b3f4a7da 100644 --- a/src/plugin/bridges/clap-impls/plugin-proxy.cpp +++ b/src/plugin/bridges/clap-impls/plugin-proxy.cpp @@ -54,9 +54,12 @@ clap_plugin_proxy::plugin_destroy(const struct clap_plugin* plugin) { assert(plugin && plugin->plugin_data); auto self = static_cast(plugin->plugin_data); - // TODO: Destroy on the Wine side + // This will clean everything related to this instance up on the Wine plugin + // host side + self->bridge_.send_main_thread_message( + clap::plugin::Destroy{.instance_id = self->instance_id()}); - // This deallocates and destroys `self` + // And this deallocates and destroys `self` self->bridge_.unregister_plugin_proxy(self->instance_id()); } diff --git a/src/wine-host/bridges/clap.cpp b/src/wine-host/bridges/clap.cpp index 47b1b985..be8f69e0 100644 --- a/src/wine-host/bridges/clap.cpp +++ b/src/wine-host/bridges/clap.cpp @@ -209,6 +209,19 @@ void ClapBridge::run() { }) .get(); }, + [&](clap::plugin::Destroy& request) + -> clap::plugin::Destroy::Response { + return main_context_ + .run_in_context([&]() { + // This calls `clap_plugin::destroy()` as part of + // cleaning up the `unique_ptr` holding the plugin + // instance pointer + unregister_plugin_instance(request.instance_id); + + return Ack{}; + }) + .get(); + }, }); } @@ -446,12 +459,8 @@ void ClapBridge::unregister_plugin_instance(size_t instance_id) { // Remove the instance from within the main IO context so // removing it doesn't interfere with the Win32 message loop - // XXX: I don't think we have to wait for the object to be - // deleted most of the time, but I can imagine a situation - // where the plugin does a host callback triggered by a - // Win32 timer in between where the above closure is being - // executed and when the actual host application context on - // the plugin side gets deallocated. + // NOTE: This will implicitly run `clap_plugin::destroy()` as part of the + // `unique_ptr`'s cleanup main_context_ .run_in_context([&, instance_id]() -> void { std::unique_lock lock(object_instances_mutex_);