As it turns out... the LLVM bitcode that Clang produces from C/C++ is already machine and platform dependent... because that's kinda what you have to do for performance.A_SN wrote: Fri Jul 08, 2022 6:46 pmI don't know about the practical aspects of accomplishing this, but compilers these days turn all code into an intermediary representation, then the IR is turned into another IR (same format) that is optimised depending on the target, then that IR is turned into whatever type of bytecode. In theory you could have plugins that represent an IR (or something that can be parsed by a LLVM parser), then the DAW could call CLAP's LLVM compiler which would compile the plugin IR into a binary, and cache the compilation for later.koalaboy wrote: Wed Jun 15, 2022 6:03 pm there's a reason that C/C++/Rust are still leading the way in performance when necessary.
CLAP: The New Audio Plug-in Standard (by U-he, Bitwig and others)
- KVRAF
- 8476 posts since 12 Feb, 2006 from Helsinki, Finland
-
- KVRian
- 1057 posts since 6 May, 2008 from Poland
Yeah but you're most likely thinking of Clang outputting a .bc file, that's not quite what I'm talking about. LLVM (not talking about Clang specifically) parses all languages into an IR, then at a later stage it turns that naive IR into an IR that is optimised according to the target architecture. So what you want into your universal plugin format is something that reflects the naive IR, which is what things like SPIR do, SPIR represents a GPU shader or kernel without anything platform-specific. Interestingly SPIR used LLVM but SPIR-V doesn't anymore (I assume they didn't want to rely on LLVM's own format so much), but the SPIR-LLVM IR can still be converted to SPIR-V. I think SPIR-V could definitely inspire what I have in mind for CLAP.mystran wrote: Fri Jul 08, 2022 7:34 pm As it turns out... the LLVM bitcode that Clang produces from C/C++ is already machine and platform dependent... because that's kinda what you have to do for performance.
It sounds like you're saying what I'm talking about isn't possible, it's already been done though, I think Google's PNaCl did something similar.
- KVRAF
- 24411 posts since 7 Jan, 2009 from Croatia
I doubt requiring regular users to have the whole LLVM installed on their machines as a prerequisite just to be able to locally compile JIT based plugins in order to bypass notarization is a good idea, but ok.
- KVRAF
- 8476 posts since 12 Feb, 2006 from Helsinki, Finland
Ofcourse you can compile to portable bytecode and then JIT that to native. JVM does that, .NET does that, emscripten does that... the list goes on and on...A_SN wrote: Fri Jul 08, 2022 7:52 pm It sounds like you're saying what I'm talking about isn't possible, it's already been done though, I think Google's PNaCl did something similar.
The question is not whether this is actually possible, but rather whether you can match the performance of C/C++ code that might be making decisions based on the platform already at the preprocessor stage.
-
- KVRian
- 1057 posts since 6 May, 2008 from Poland
That's absolutely not how it works, I wish you would all become more familiar with the topic before making conclusions or dismissing anything. The CLAP library used by the DAW would include whatever parts of LLVM (which is a set of libraries, not a program) it needs go compile from IR to native binary (it's not even that big due to not containing all the big language parsing stuff). So it's just a library that CLAP would use, nothing extraordinary about this. Again, that kind of approach is common enough, your GPU drivers have LLVM included for compiling shaders and kernels, there's no such thing as having "the whole LLVM installed" for this (I assume you said this because you're thinking of how your system's package manager let's you install "LLVM").EvilDragon wrote: Fri Jul 08, 2022 8:10 pm I doubt requiring regular users to have the whole LLVM installed on their machines as a prerequisite just to be able to locally compile JIT based plugins in order to bypass notarization is a good idea, but ok.
Oh and it's not "just to bypass notarisation", as people have said in this thread weeks ago you need such an approach now. This isn't the 1990s anymore, "one binary for one platform supported" isn't good enough in the 2020s. I already made points about futureproofing through this approach.
And yet that's not what I'm talking about. I'm not talking about interpreting a portable bytecode JIT like WebAssembly does, I'm talking about compiling an intermediate representation to a native binary machine code blob, then running that. Again, that's the SPIR approach (and apparently what PNaCl also did). I wish you knew more about the topic.mystran wrote: Fri Jul 08, 2022 8:19 pm Ofcourse you can compile to portable bytecode and then JIT that to native. JVM does that, .NET does that, emscripten does that... the list goes on and on...
The question is not whether this is actually possible, but rather whether you can match the performance of C/C++ code that might be making decisions based on the platform already at the preprocessor stage.
So in that case, like I've already said before, you're moving part of the compilation from the dev's machine to the user's machine, with the advantage that you can target the user's specific architecture (kind of like Homebrew does as opposed to downloading binaries, but that's something else), so it's exactly the same result except you can better target the architecture.
As for the preprocessor thing, well, yeah your code won't know anything about the machine it's on at that stage, but there are alternatives (for instance like how you can detect CPU instruction set at run time), and it's not such a big deal. I can think of an example where that could be a slight problem (for instance in my endianness-sensitive code I have a macro for assuming LE or not assuming endianness), but I can't imagine this being a big deal.
-
- KVRian
- 1213 posts since 25 Dec, 2018
Which is why, in fact, we did consider itA_SN wrote: Fri Jul 08, 2022 5:14 pmDamn shame, I thought maybe whoever makes a new plugin format in the 2020s would consider making a portable interpreted plugin format, so you could have a plugin that works on any platform, even on a WebAssembly host (I feel strongly that WebAssembly is the future that will allow me to soft-ditch macOS).
Nothing stops you compiling a clap to wasm today.
Whether there is a daw which can run wasm directky at audio rate is a separate issue. There isn’t. Today.
-
- KVRAF
- 7577 posts since 17 Feb, 2005
I have a simple question that hopefully isn't off topic, but have not seen addressed by anyone who is currently compiling CLAP plugins. Are symbol exports destined to follow a prescribed rule on decorations? I think some of my plugins in the past had problems because of MinGW not following the MSVC symbol decorations.
-
Jeff McClintock Jeff McClintock https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=56398
- KVRist
- 432 posts since 30 Jan, 2005 from New Zealand
I was thinking about this. People can write extensions however they like right? And an extension is just a list of function pointers. So the author of a CLAP extension could choose to use the same trick as COM (make a C struct that is laid out exactly like a C++ interface).mystran wrote: Fri Jul 08, 2022 11:14 am I guess the argument here is that you can't directly turn extensions into interfaces and pass vtables because the 'this' pointers would have wrong offsets as all the CLAP methods take the same 'clap_plugin_t' pointer?
It still 100% qualifies as a regular CLAP extension. (clap_plugin_t has no virtual methods of its own, so there is no compatibility issues there I think. Probly need to try it to be sure.).
With this one simple trick - either plugin, or host, or both can opt-in to calling the extension directly via the high-efficiency C++ interface.
If you do this, then VST3 doesn't get to claim to be the more efficient calling convention any longer
For sure, if you write a plugin directly in a C style (no C++ objects) - you don't pay the overhead of a 'helper' to convert from C to C++. But realistically, a large segment of our industry writes plugins in C++, using classes and objects. They are worth considering.mystran wrote: Fri Jul 08, 2022 11:14 am That's true.. but you don't need to go through the vtable at all if you instead just populate the extensions with pointers to regular (non-virtual) or static methods.
- KVRAF
- 8476 posts since 12 Feb, 2006 from Helsinki, Finland
If you write your own extensions.. then sure.. but to get anything done you have to support a couple of standard extensions (eg. audio ports, probably parameters, note ports for instruments, gui if you want such a thing) which all take a pointer to the plugin as the first argument to every method.Jeff McClintock wrote: Fri Jul 08, 2022 10:56 pmI was thinking about this. People can write extensions however they like right? And an extension is just a list of function pointers. So the author of a CLAP extension could choose to use the same trick as COM (make a C struct that is laid out exactly like a C++ interface).mystran wrote: Fri Jul 08, 2022 11:14 am I guess the argument here is that you can't directly turn extensions into interfaces and pass vtables because the 'this' pointers would have wrong offsets as all the CLAP methods take the same 'clap_plugin_t' pointer?
So .. I posted the basic idea above, but.. here's my "zero-cost" wrapper (ie. all the 'helpers' are supposed to either inline or compile into a trivial tail-calls = regular direct jumps) so far:For sure, if you write a plugin directly in a C style (no C++ objects) - you don't pay the overhead of a 'helper' to convert from C to C++. But realistically, a large segment of our industry writes plugins in C++, using classes and objects. I don't think the industry is moving back to C.mystran wrote: Fri Jul 08, 2022 11:14 am That's true.. but you don't need to go through the vtable at all if you instead just populate the extensions with pointers to regular (non-virtual) or static methods.
https://github.com/signaldust/clap-glue [edit: now a proper repo]
Basically implement an object with all the methods you need (including whatever extensions you want) then in plug_get_extension query extensions with ClapExt_Whatever<MyPlug>::check(id) to get the relevant table to generate (at which point the compiler will also check that you really implemented the stuff).. and then just declare a global factory object (one per plugin class) like this:
Code: Select all
static ClapFactory<MyPlug> test_factory;edit: Just for emphasis.. you absolutely CAN do things like implement general GUI support once and then just derive your plugin from a base-class that brings that functionality in... so it's not like you lose inheritance, you just don't need a vtable for that anymore.
Last edited by mystran on Sat Jul 09, 2022 1:55 pm, edited 1 time in total.
-
Jeff McClintock Jeff McClintock https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=56398
- KVRist
- 432 posts since 30 Jan, 2005 from New Zealand
yeah, I had my hopes up, but I think you are correctmystran wrote: Fri Jul 08, 2022 11:56 pm If you write your own extensions.. then sure.. but to get anything done you have to support a couple of standard extensions .. which all take a pointer to the plugin as the first argument to every method.
- KVRist
- 211 posts since 3 Jan, 2021
Still too bad something like LV2 Atoms where never considered, they are ultimately the most flexible way to provide (or ignore) functionality: http://lv2plug.in/ns/ext/atom
Heck, you could have two plugins communicate information on a Host that doesn't even support that Atom format. Not something I see possible with CLAP. ("maybe with an extension" << yeah but it's a core concept of the entire format. not something you can simply bolt on
)
Heck, you could have two plugins communicate information on a Host that doesn't even support that Atom format. Not something I see possible with CLAP. ("maybe with an extension" << yeah but it's a core concept of the entire format. not something you can simply bolt on
-
- KVRian
- 1213 posts since 25 Dec, 2018
There’s only one symbol you need to export, which is the clap entry data structure. I don’t know if anyone has built with mingw on windows yet but if the export macros in the clap headers need adjusting for that toolchain just hit us up on github and I’m sure we can figure it out.camsr wrote: Fri Jul 08, 2022 10:37 pm I have a simple question that hopefully isn't off topic, but have not seen addressed by anyone who is currently compiling CLAP plugins. Are symbol exports destined to follow a prescribed rule on decorations? I think some of my plugins in the past had problems because of MinGW not following the MSVC symbol decorations.
- KVRAF
- 24411 posts since 7 Jan, 2009 from Croatia
Erm, aren't LV2 atoms an extension bolted on to the core LV2 spec? I mean it's even in the link you posted, "ext"DRMR wrote: Sat Jul 09, 2022 7:34 am("maybe with an extension" << yeah but it's a core concept of the entire format
-
Zaphod (giancarlo) Zaphod (giancarlo) https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=111268
- KVRAF
- 2610 posts since 23 Jun, 2006
I understand how it works, but i’m not sure this is what Apple wants.A_SN wrote: Fri Jul 08, 2022 8:34 pmThat's absolutely not how it works, I wish you would all become more familiar with the topic before making conclusions or dismissing anything. The CLAP library used by the DAW would include whatever parts of LLVM (which is a set of libraries, not a program) it needs go compile from IR to native binary (it's not even that big due to not containing all the big language parsing stuff). So it's just a library that CLAP would use, nothing extraordinary about this. Again, that kind of approach is common enough, your GPU drivers have LLVM included for compiling shaders and kernels, there's no such thing as having "the whole LLVM installed" for this (I assume you said this because you're thinking of how your system's package manager let's you install "LLVM").EvilDragon wrote: Fri Jul 08, 2022 8:10 pm I doubt requiring regular users to have the whole LLVM installed on their machines as a prerequisite just to be able to locally compile JIT based plugins in order to bypass notarization is a good idea, but ok.
Oh and it's not "just to bypass notarisation", as people have said in this thread weeks ago you need such an approach now. This isn't the 1990s anymore, "one binary for one platform supported" isn't good enough in the 2020s. I already made points about futureproofing through this approach.
And yet that's not what I'm talking about. I'm not talking about interpreting a portable bytecode JIT like WebAssembly does, I'm talking about compiling an intermediate representation to a native binary machine code blob, then running that. Again, that's the SPIR approach (and apparently what PNaCl also did). I wish you knew more about the topic.mystran wrote: Fri Jul 08, 2022 8:19 pm Ofcourse you can compile to portable bytecode and then JIT that to native. JVM does that, .NET does that, emscripten does that... the list goes on and on...
The question is not whether this is actually possible, but rather whether you can match the performance of C/C++ code that might be making decisions based on the platform already at the preprocessor stage.
So in that case, like I've already said before, you're moving part of the compilation from the dev's machine to the user's machine, with the advantage that you can target the user's specific architecture (kind of like Homebrew does as opposed to downloading binaries, but that's something else), so it's exactly the same result except you can better target the architecture.
As for the preprocessor thing, well, yeah your code won't know anything about the machine it's on at that stage, but there are alternatives (for instance like how you can detect CPU instruction set at run time), and it's not such a big deal. I can think of an example where that could be a slight problem (for instance in my endianness-sensitive code I have a macro for assuming LE or not assuming endianness), but I can't imagine this being a big deal.
- KVRAF
- 8476 posts since 12 Feb, 2006 from Helsinki, Finland
