Preloader extension (name TBD) for background operations #485
+391
−1
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Following the discussion in #484, this is a set of extensions (and factory) that provide a way for hosts to perform various expensive plugin operations (e.g. loading, saving, etc.) in a background thread or thread pool.
The full design is detailed in
preloader.h, but in short, the idea is to introduce a small object that can contain the state of a plugin instance, perform the expensive work off of the main thread, and come back to the main thread only to synchronize with a plugin instance.I've named this "Preloader" for now, but this isn't a very good name since it can do more than just pre-loading, so ideas on how to better call this are welcome. 🙂
Compared to the design in #343, this does not change the thread classes of any existing functions, nor does it "lock" the plugin instance in a "background operation" mode. This completely avoids the issues raised in #343 of e.g. using host callbacks, timers, processing, etc.
For the plugin instance, it's just business as usual until the Preloader comes in for synchronizing (i.e. Commit or Snapshot operation), which always happens on the
[main-thread], so no thread-switching or special synchronization is needed there.In fact, this approach is heavily inspired by the existing rules around
[audio-thread]operation, where this part of the plugin can "live" on a separate thread (or thread pool), but is completely non-concurrent.This makes the implementation much easier:
[audio-thread], they can re-use their existing infrastructure (e.g. thread pools and channels), only for a different thread (pool) dedicated to long-running, non-realtime background operation.On top of that, Preloaders make use of the familiar CLAP extension system to expose to the host which background operations are supported.
There is no "required" set of extensions needed to make it work, so plugins can choose to implement only what they really need to be offloaded to a background thread.
On top of the
preloaderextension and thepreloader-factory, this PR introduces two "Preloader extensions" to start:clap_plugin_preloader_state: Allows loading & saving plugin state into/from a preloader from a background thread;clap_preloader_activate: Allows to preallocate e.g. buffers or other ressources from a background thread, to make calls toactivatefaster.Other extensions may have "preloader" variants added in the future for background operation, here's a few ideas:
log: would be helpful to have logging facilities available in background threads (we could keep the same interface there tbh)state-context: to be on-par with the current[main-thread]versions;thread-checkgui: we could allow some GUI resources needed forclap_gui.createto be created/loaded in the background, e.g. assets, fonts, and possibly some GPU resources for when multithread-compatible APIs are used (e.g. Vulkan, Metal, DX12).Also to note, I've tested and used this internally for a while, but I've only just cleaned it up a bit following the discussion in #484, so feel free to also request changes in code organization and such.