Skip to content

Conversation

@prokopyl
Copy link
Contributor

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:

  • For plugins, no synchronization primitives are needed, it's just Plain Old Data internally, everything is handled by the host;
  • For hosts, since this is essentially the same rules as for [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 preloader extension and the preloader-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 to activate faster.

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-check
  • gui: we could allow some GUI resources needed for clap_gui.create to 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).
  • More? 🙂

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant