DPF

DISTRHO Plugin Framework
Log | Files | Refs | Submodules | README | LICENSE

commit 4893656da0f83c16ed1e1f11a8dd87f1cb483a79
parent d9044f27fe462d1827a8fcd2a2fa0bf988c0067f
Author: falkTX <falktx@falktx.com>
Date:   Sat,  2 Oct 2021 04:36:38 +0100

A few more VST3 tests on refcounter and host context

Signed-off-by: falkTX <falktx@falktx.com>

Diffstat:
Mdistrho/src/DistrhoPluginVST3.cpp | 60+++++++++++++++++++++++++++++++++++++++++++-----------------
Mdistrho/src/DistrhoUIVST3.cpp | 107++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Mdistrho/src/travesty/factory.h | 2+-
3 files changed, 118 insertions(+), 51 deletions(-)

diff --git a/distrho/src/DistrhoPluginVST3.cpp b/distrho/src/DistrhoPluginVST3.cpp @@ -2311,13 +2311,16 @@ struct dpf_dsp_connection_point : v3_connection_point_cpp { DISTRHO_SAFE_ASSERT_RETURN(point != nullptr, V3_NOT_INITIALIZED); DISTRHO_SAFE_ASSERT_RETURN(point->other != nullptr, V3_INVALID_ARG); - point->other = nullptr; - point->bridge = nullptr; - if (point->type == kConnectionPointComponent) if (PluginVst3* const vst3 = point->vst3) vst3->disconnect(); + if (point->type == kConnectionPointBridge) + v3_cpp_obj_unref(point->other); + + point->other = nullptr; + point->bridge = nullptr; + return V3_OK; } @@ -2453,13 +2456,15 @@ struct dpf_edit_controller : v3_edit_controller_cpp { bool initialized; // cached values v3_component_handler** handler; + v3_host_application** const originalHostContext; v3_plugin_base::v3_funknown** hostContext; - dpf_edit_controller(ScopedPointer<PluginVst3>& v) + dpf_edit_controller(ScopedPointer<PluginVst3>& v, v3_host_application** const h) : refcounter(1), vst3(v), initialized(false), handler(nullptr), + originalHostContext(h), hostContext(nullptr) { // v3_funknown, single instance with custom query @@ -2757,10 +2762,14 @@ struct dpf_edit_controller : v3_edit_controller_cpp { DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, nullptr); // we require host context for message creation - DISTRHO_SAFE_ASSERT_RETURN(controller->hostContext != nullptr, nullptr); - v3_host_application** host = nullptr; - v3_cpp_obj_query_interface(controller->hostContext, v3_host_application_iid, &host); + + if (controller->hostContext != nullptr) + v3_cpp_obj_query_interface(controller->hostContext, v3_host_application_iid, &host); + + if (host == nullptr) + host = controller->originalHostContext; + DISTRHO_SAFE_ASSERT_RETURN(host != nullptr, nullptr); // if there is a component connection, we require it to be active @@ -3031,10 +3040,12 @@ struct dpf_component : v3_component_cpp { #endif ScopedPointer<dpf_edit_controller> controller; ScopedPointer<PluginVst3> vst3; + v3_host_application** const hostContext; - dpf_component(ScopedPointer<dpf_component>* const s) + dpf_component(ScopedPointer<dpf_component>* const s, v3_host_application** const h) : refcounter(1), - self(s) + self(s), + hostContext(h) { // v3_funknown, everything custom query_interface = query_interface_component; @@ -3109,7 +3120,7 @@ struct dpf_component : v3_component_cpp { if (v3_tuid_match(iid, v3_edit_controller_iid)) { if (component->controller == nullptr) - component->controller = new dpf_edit_controller(component->vst3); + component->controller = new dpf_edit_controller(component->vst3, component->hostContext); else ++component->controller->refcounter; *iface = &component->controller; @@ -3225,6 +3236,9 @@ struct dpf_component : v3_component_cpp { v3_host_application** host = nullptr; v3_cpp_obj_query_interface(context, v3_host_application_iid, &host); + if (host == nullptr) + host = component->hostContext; + component->vst3 = new PluginVst3(host); return V3_OK; } @@ -3373,9 +3387,6 @@ static const PluginExporter& _getPluginInfo() d_lastSampleRate = 0.0; d_lastCanRequestParameterValueChanges = false; - dpf_tuid_class[2] = dpf_tuid_component[2] = dpf_tuid_controller[2] - = dpf_tuid_processor[2] = dpf_tuid_view[2] = gPluginInfo.getUniqueId(); - return gPluginInfo; } @@ -3389,12 +3400,19 @@ static const PluginExporter& getPluginInfo() // dpf_factory struct dpf_factory : v3_plugin_factory_cpp { + // cached values + v3_funknown** hostContext; + dpf_factory() + : hostContext(nullptr) { static constexpr const v3_tuid interface_v1 = V3_ID_COPY(v3_plugin_factory_iid); static constexpr const v3_tuid interface_v2 = V3_ID_COPY(v3_plugin_factory_2_iid); static constexpr const v3_tuid interface_v3 = V3_ID_COPY(v3_plugin_factory_3_iid); + dpf_tuid_class[2] = dpf_tuid_component[2] = dpf_tuid_controller[2] + = dpf_tuid_processor[2] = dpf_tuid_view[2] = getPluginInfo().getUniqueId(); + // v3_funknown, used statically query_interface = dpf_static__query_interface<interface_v1, interface_v2, interface_v3>; ref = dpf_static__ref; @@ -3476,8 +3494,12 @@ struct dpf_factory : v3_plugin_factory_cpp { dpf_factory* const factory = *(dpf_factory**)self; DISTRHO_SAFE_ASSERT_RETURN(factory != nullptr, V3_NOT_INITIALIZED); + // query for host context + v3_host_application** host = nullptr; + v3_cpp_obj_query_interface(factory->hostContext, v3_host_application_iid, &host); + ScopedPointer<dpf_component>* const componentptr = new ScopedPointer<dpf_component>; - *componentptr = new dpf_component(componentptr); + *componentptr = new dpf_component(componentptr, host); *instance = componentptr; return V3_OK; } @@ -3524,10 +3546,14 @@ struct dpf_factory : v3_plugin_factory_cpp { return V3_OK; } - static V3_API v3_result set_host_context(void* self, v3_funknown* host) + static V3_API v3_result set_host_context(void* self, v3_funknown** context) { - d_stdout("dpf_factory::set_host_context => %p %p", self, host); - return V3_NOT_IMPLEMENTED; + d_stdout("dpf_factory::set_host_context => %p %p", self, context); + dpf_factory* const factory = *(dpf_factory**)self; + DISTRHO_SAFE_ASSERT_RETURN(factory != nullptr, V3_NOT_INITIALIZED); + + factory->hostContext = context; + return V3_OK; } DISTRHO_PREVENT_HEAP_ALLOCATION diff --git a/distrho/src/DistrhoUIVST3.cpp b/distrho/src/DistrhoUIVST3.cpp @@ -30,6 +30,7 @@ namespace std { explicit atomic_int(volatile int v) noexcept : value(v) {} int operator++() volatile noexcept { return __atomic_add_fetch(&value, 1, __ATOMIC_RELAXED); } int operator--() volatile noexcept { return __atomic_sub_fetch(&value, 1, __ATOMIC_RELAXED); } + operator int() volatile noexcept { return __atomic_load_n(&value, __ATOMIC_RELAXED); } }; }; #endif @@ -593,22 +594,39 @@ static V3_API uint32_t dpf_static__ref(void*) { return 1; } static V3_API uint32_t dpf_static__unref(void*) { return 0; } // -------------------------------------------------------------------------------------------------------------------- +// v3_funknown with refcounter + +template<class T> +static V3_API uint32_t dpf_refcounter__ref(void* self) +{ + return ++(*(T**)self)->refcounter; +} + +template<class T> +static V3_API uint32_t dpf_refcounter__unref(void* self) +{ + return --(*(T**)self)->refcounter; +} + +// -------------------------------------------------------------------------------------------------------------------- // dpf_ui_connection_point struct dpf_ui_connection_point : v3_connection_point_cpp { + std::atomic_int refcounter; ScopedPointer<UIVst3>& uivst3; v3_connection_point** other; dpf_ui_connection_point(ScopedPointer<UIVst3>& v) - : uivst3(v), + : refcounter(1), + uivst3(v), other(nullptr) { static constexpr const v3_tuid interface = V3_ID_COPY(v3_connection_point_iid); // v3_funknown, single instance query_interface = dpf_static__query_interface<interface>; - ref = dpf_static__ref; - unref = dpf_static__unref; + ref = dpf_refcounter__ref<dpf_ui_connection_point>; + unref = dpf_refcounter__unref<dpf_ui_connection_point>; // v3_connection_point point.connect = connect; @@ -665,20 +683,22 @@ struct dpf_ui_connection_point : v3_connection_point_cpp { // dpf_plugin_view_content_scale struct dpf_plugin_view_content_scale : v3_plugin_view_content_scale_cpp { + std::atomic_int refcounter; ScopedPointer<UIVst3>& uivst3; // cached values float scaleFactor; dpf_plugin_view_content_scale(ScopedPointer<UIVst3>& v) - : uivst3(v), + : refcounter(1), + uivst3(v), scaleFactor(0.0f) { static constexpr const v3_tuid interface = V3_ID_COPY(v3_plugin_view_content_scale_iid); // v3_funknown, single instance query_interface = dpf_static__query_interface<interface>; - ref = dpf_static__ref; - unref = dpf_static__unref; + ref = dpf_refcounter__ref<dpf_plugin_view_content_scale>; + unref = dpf_refcounter__unref<dpf_plugin_view_content_scale>; // v3_plugin_view_content_scale scale.set_content_scale_factor = set_content_scale_factor; @@ -751,7 +771,7 @@ static const char* const kSupportedPlatforms[] = { struct dpf_plugin_view : v3_plugin_view_cpp { std::atomic_int refcounter; - ScopedPointer<dpf_plugin_view>* self; + dpf_plugin_view** const self; ScopedPointer<dpf_ui_connection_point> connection; ScopedPointer<dpf_plugin_view_content_scale> scale; #ifdef DPF_VST3_USING_HOST_RUN_LOOP @@ -762,12 +782,11 @@ struct dpf_plugin_view : v3_plugin_view_cpp { v3_host_application** const host; void* const instancePointer; double sampleRate; - v3_plugin_frame** frame = nullptr; + v3_plugin_frame** frame; - dpf_plugin_view(ScopedPointer<dpf_plugin_view>* selfptr, - v3_host_application** const h, void* const instance, const double sr) + dpf_plugin_view(dpf_plugin_view** const s, v3_host_application** const h, void* const instance, const double sr) : refcounter(1), - self(selfptr), + self(s), host(h), instancePointer(instance), sampleRate(sr), @@ -843,7 +862,7 @@ struct dpf_plugin_view : v3_plugin_view_cpp { static V3_API uint32_t unref_view(void* self) { - ScopedPointer<dpf_plugin_view>* const viewptr = (ScopedPointer<dpf_plugin_view>*)self; + dpf_plugin_view** const viewptr = (dpf_plugin_view**)self; dpf_plugin_view* const view = *viewptr; if (const int refcount = --view->refcounter) @@ -854,11 +873,31 @@ struct dpf_plugin_view : v3_plugin_view_cpp { d_stdout("dpf_plugin_view::unref => %p | refcount is zero, deleting everything now!", self); + DISTRHO_SAFE_ASSERT_RETURN(viewptr == view->self, V3_INTERNAL_ERR); + if (view->connection != nullptr && view->connection->other) v3_cpp_obj(view->connection->other)->disconnect(view->connection->other, (v3_connection_point**)&view->connection); - *(view->self) = nullptr; + if (dpf_ui_connection_point* const conn = view->connection) + { + if (const int refcount = conn->refcounter) + { + d_stderr("DPF warning: asked to delete view while connection point still active (refcount %d)", refcount); + return V3_INVALID_ARG; + } + } + + if (dpf_plugin_view_content_scale* const scale = view->scale) + { + if (const int refcount = scale->refcounter) + { + d_stderr("DPF warning: asked to delete view while content scale still active (refcount %d)", refcount); + return V3_INVALID_ARG; + } + } + + delete view; delete viewptr; return 0; } @@ -879,7 +918,7 @@ struct dpf_plugin_view : v3_plugin_view_cpp { } return V3_NOT_IMPLEMENTED; - }; + } static V3_API v3_result attached(void* self, void* parent, const char* platform_type) { @@ -892,14 +931,14 @@ struct dpf_plugin_view : v3_plugin_view_cpp { { if (std::strcmp(kSupportedPlatforms[i], platform_type) == 0) { - #ifdef DPF_VST3_USING_HOST_RUN_LOOP + #ifdef DPF_VST3_USING_HOST_RUN_LOOP // find host run loop to plug ourselves into (required on some systems) DISTRHO_SAFE_ASSERT_RETURN(view->frame != nullptr, V3_INVALID_ARG); v3_run_loop** runloop = nullptr; v3_cpp_obj_query_interface(view->frame, v3_run_loop_iid, &runloop); DISTRHO_SAFE_ASSERT_RETURN(runloop != nullptr, V3_INVALID_ARG); - #endif + #endif const float scaleFactor = view->scale != nullptr ? view->scale->scaleFactor : 0.0f; view->uivst3 = new UIVst3((v3_plugin_view**)view->self, @@ -915,20 +954,20 @@ struct dpf_plugin_view : v3_plugin_view_cpp { view->uivst3->setFrame(view->frame); - #ifdef DPF_VST3_USING_HOST_RUN_LOOP + #ifdef DPF_VST3_USING_HOST_RUN_LOOP // register a timer host run loop stuff view->timer = new dpf_timer_handler(view->uivst3); v3_cpp_obj(runloop)->register_timer(runloop, (v3_timer_handler**)&view->timer, DPF_VST3_TIMER_INTERVAL); - #endif + #endif return V3_OK; } } return V3_NOT_IMPLEMENTED; - }; + } static V3_API v3_result removed(void* self) { @@ -937,21 +976,23 @@ struct dpf_plugin_view : v3_plugin_view_cpp { DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALIZED); DISTRHO_SAFE_ASSERT_RETURN(view->uivst3 != nullptr, V3_INVALID_ARG); - #ifdef DPF_VST3_USING_HOST_RUN_LOOP + #ifdef DPF_VST3_USING_HOST_RUN_LOOP // unregister our timer as needed if (view->timer != nullptr) { v3_run_loop** runloop = nullptr; - if (v3_cpp_obj_query_interface(view->host, v3_run_loop_iid, &runloop) == V3_OK && runloop != nullptr) + v3_cpp_obj_query_interface(view->host, v3_run_loop_iid, &runloop); + + if (runloop != nullptr) v3_cpp_obj(runloop)->unregister_timer(runloop, (v3_timer_handler**)&view->timer); view->timer = nullptr; } - #endif + #endif view->uivst3 = nullptr; return V3_OK; - }; + } static V3_API v3_result on_wheel(void* self, float distance) { @@ -963,7 +1004,7 @@ struct dpf_plugin_view : v3_plugin_view_cpp { DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALIZED); return uivst3->onWheel(distance); - }; + } static V3_API v3_result on_key_down(void* self, int16_t key_char, int16_t key_code, int16_t modifiers) { @@ -975,7 +1016,7 @@ struct dpf_plugin_view : v3_plugin_view_cpp { DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALIZED); return uivst3->onKeyDown(key_char, key_code, modifiers); - }; + } static V3_API v3_result on_key_up(void* self, int16_t key_char, int16_t key_code, int16_t modifiers) { @@ -987,7 +1028,7 @@ struct dpf_plugin_view : v3_plugin_view_cpp { DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALIZED); return uivst3->onKeyUp(key_char, key_code, modifiers); - }; + } static V3_API v3_result get_size(void* self, v3_view_rect* rect) { @@ -1007,7 +1048,7 @@ struct dpf_plugin_view : v3_plugin_view_cpp { rect->right = tmpUI.getWidth(); rect->bottom = tmpUI.getHeight(); return V3_OK; - }; + } static V3_API v3_result on_size(void* self, v3_view_rect* rect) { @@ -1019,7 +1060,7 @@ struct dpf_plugin_view : v3_plugin_view_cpp { DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALIZED); return uivst3->onSize(rect); - }; + } static V3_API v3_result on_focus(void* self, v3_bool state) { @@ -1031,7 +1072,7 @@ struct dpf_plugin_view : v3_plugin_view_cpp { DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALIZED); return uivst3->onFocus(state); - }; + } static V3_API v3_result set_frame(void* self, v3_plugin_frame** frame) { @@ -1045,7 +1086,7 @@ struct dpf_plugin_view : v3_plugin_view_cpp { return uivst3->setFrame(frame); return V3_NOT_INITIALIZED; - }; + } static V3_API v3_result can_resize(void* self) { @@ -1055,7 +1096,7 @@ struct dpf_plugin_view : v3_plugin_view_cpp { // #else return V3_NOT_IMPLEMENTED; // #endif - }; + } static V3_API v3_result check_size_constraint(void* self, v3_view_rect* rect) { @@ -1067,7 +1108,7 @@ struct dpf_plugin_view : v3_plugin_view_cpp { DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALIZED); return uivst3->checkSizeConstraint(rect); - }; + } }; // -------------------------------------------------------------------------------------------------------------------- @@ -1079,7 +1120,7 @@ v3_plugin_view** dpf_plugin_view_create(v3_host_application** const host, void* const instancePointer, const double sampleRate) { - ScopedPointer<dpf_plugin_view>* const viewptr = new ScopedPointer<dpf_plugin_view>; + dpf_plugin_view** const viewptr = new dpf_plugin_view*; *viewptr = new dpf_plugin_view(viewptr, host, instancePointer, sampleRate); return (v3_plugin_view**)static_cast<void*>(viewptr); } diff --git a/distrho/src/travesty/factory.h b/distrho/src/travesty/factory.h @@ -96,7 +96,7 @@ struct v3_plugin_factory_3 { struct v3_plugin_factory_2; v3_result (V3_API *get_class_info_utf16)(void* self, int32_t idx, struct v3_class_info_3*); - v3_result (V3_API *set_host_context)(void* self, struct v3_funknown* host); + v3_result (V3_API *set_host_context)(void* self, struct v3_funknown** host); }; static constexpr const v3_tuid v3_plugin_factory_3_iid =