October 16, 2015
I posted a couple months back about using OpenGL in a VST plugin; your answers were really helpful so thank you for the assistance there! I've had a lot of progress since then.
I'm working on a VST3 plugin with a VST2 wrapper which uses OpenGL, GLEW, and GLFW, all of which I'm currently linking dynamically. When I'm running through a test host (Cantabile 2.0) in Visual Studio, I have the external dlls in the proper place (in the same location as the dll I'm generating) and Visual Studio can find them fine when I'm debugging through Cantabile.
When I try to load up the plugin in Ableton though, it can't find the external dlls and won't load my plugin. I was able to solve the issue by copying the external dlls to the same folder as Ableton's .exe is in (got the idea from here: https://msdn.microsoft.com/en-us/library/7d83bc18.aspx) and got the plugin up and running fine. But manually copying the dlls to the right directory isn't a proper solution in a "real world" plugin, and I'm sure there must be a proper way to do it.
I'd imagine when a plugin uses dynamically linked libraries it does some configuration during installation to tell the OS or Ableton where to find the libraries, or that an OS has a specified place to copy the dlls to during installation. What is the proper way to make sure Ableton and/or the OS (I'm not sure which is doing the searching) can find my dlls?
I realize I could just link statically instead, but I believe GLFW at the least recommends dynamic linking, though the reason's slipping my mind. I could be completely wrong.
January 29, 2017
Generally, you would like to link to static libs so that your plugin is one DLL file only to install/instantiate. However, sometimes this is not feasible so you would need to create an installer to dump your dependent DLLs into a folder. This varies from OS to OS, the easiest solution being to place the extra DLLs in the same folder as the plugin DLL (eg /Program Files/Common/VST3 for Windows). However, most users understand how to move their plugin DLLs to their various VST2 and VST3 folders, as you can have multiple plugin folders if you like, but they would not understand having to move other dependent DLLs as well. Obviously, the problem is that your compiled DLL will need to know the folder path, or be able to query for it, at runtime rather than compile time.
In WinOS (which is what I think you are targeting), you can use the APPDATA folder paradigm where the DLL can find the user-data folder with an OS query (this is how RackAFX stores its user-folders and user-data).
The client (Ableton) should not be involved in your extra DLLs. The client will instantiate your plugin knowing only the filename. If your plugin requires loading dependent DLLs at instantiation time, then that is your problem, not the client's.
Note that VST3 uses the class-factory paradigm, so you can generally not use singletons or other anti-patterns for data or object storage.
April 3, 2014
for glew you can compile and link the glew.c file into your plugin, that's the easiest way and I have successfully done it to fetch "advanced" opengl function pointers in a VST plugin. I never used GLFW myself, but it has a zlib license, so you can link it directly into your plugin, too.
Placing the additional DLLs is host dependent so in general you can't assume any place for the host to look in. E.g. Cubase will not add the VST folders to the DLL searchpath, so simply copying them into the same folder as the plugin .DLL/.vst3 file will not always work. It may even work sometimes, as another plugin may already have added the VST folder to the DLL search path!
What you basically would have to do is write a wrapper plugin that first sets the OS DLL search path (you have to get the path from somewhere of course, e.g. registry or force the installation in the APPDATA folder as Will suggested and hardcode it) and then loads your real plugin dll dynamically. On Windows the functions you need are LoadLibrary and SetDllDirectory or better AddDllDirectory (remember that you are messing around in the host's environment in that moment!).
But as I said - if you don't absolutely have to load additional DLLs, better avoid it
January 29, 2017
I agree with Tom - you really want only one DLL to load. Querying the registry for path information is not rocket-science but can be tricky. I can give you the code for that kind of thing, but I'd avoid it if possible (RackAFX queries the registry for the location of your compiler's EXE, but that's about all I use the registry for).
October 16, 2015
Thanks for your replies!
Sounds like any reasons I might have for dynamic linking are outweighed by the difficulty it causes finding the dlls, so I'll switch to static linking. I'd rather avoid having to write OS-dependent code (we do want the plugin to run on Windows and Mac OS) but I haven't even ported the code to Mac side to get it compiling in XCode yet. I'd like that process to be quick and easy though! So static linking is the way to go.
October 16, 2015
Will, I re-read your first reply and realized I really should have asked - why should I not use singletons? I'm using a singleton pattern right now for a print/debug log that prints to the plugin GUI, and the same class manages an ofstream for writing a debug log file where I write to and flush the file stream each time something new should be logged. The GUI must be assigned to manually before any GUI logging can be done (through a static function within the singleton class), and the ofstream is opened the first time you send a string to it for logging and left open until the plugin is closed. Regardless I'm definitely using static functions and variables. So far that's been working perfectly fine - is that just a matter of luck in the program's memory layout, and could it become problematic? What exactly should I be avoiding in a singleton pattern?
April 3, 2014
I know you asked Will, but I will give my opinion on the singleton pattern here: In my opinion there's rarely a case in C++ where a singleton makes sense (or lets say a singleton on it's own rarely makes sense). Historically this patterns comes from pure object oriented languages, where this is the only way to access gobal resources. But with C++ (which is more of a "multi-paradigm" language) you can have objects on the stack, you have statics and anonymous namespaces.
There's so much that can go wrong with a naive singleton implementation in C++, especially when threading is involved. I don't want to stop you from diving into the dirty parts of C++ programming 😉 Just a word of warning - in most cases "singeltons" are a sign for something lacking in your design because at the point you want to introduce the singelton, your object doesn't know the instance of the "singleton" class it should talk to. Why doesn't it? Most probably because of an error in your design. Logging is of course the number one textbook example for singletons. But as you said, when you use static methods and variables, is it a singleton really? When you assign "the" singleton to your GUI - why does it need to be a singleton? You could just assign an instance of your logger class there. When you want to share the ofstream with multiple instances of your plugin you would need much more synchronization, and a singleton won't solve this. You will get into race conditions when you open multiple plugin instances.
What Will was referring to why you can't use a singleton between multiple instances of you plugin is that your host will call your DLL's GetPluginFactory method and then instantiate instances from there. Things get very complex at this point. There are different DLL attach/detach points that the OS will call for different threads/process accessing the same DLL. In the end it is very difficult to tell whether multiple instances of a plugin will actually see the same or just "equal" instances of your singleton. And this behaviour may be differnt for MacOS then for Windows (e.g. shared static variables betwen DLLs behave differently and you run into lots of "undefined" behaviour in that area)
But play around with the structures and find a way that works. In the end it doesn't matter if the structure really is a "singleton" or just "something" .
The main concern about using a "singleton" is in m xopinion, that often there is a misconception and a false impression of safety connected to that pattern. But with C++ it's really not much that a singleton (on it's own) could help you with!
January 29, 2017
I agree with Tom.
I was first introduced to singletons in iOS programming (see the Conway & Hillegass books) years ago, and have tried using them in C++, but found too many issues when implementing libraries (both LIBs and DLLs). So I don't use them anymore for C++ and only rarely in iOS. In a standalone product like RackAFX, there is no need for singletons.
That said, there are singleton-die-hards out there who will want to disagree...
October 16, 2015
Thanks Tom, you brought up a lot of cases I didn't consider, especially with multiple plugin instances. I don't anticipate the end user ever wanting multiple instances of the particular plugin we're working on, but the design argument definitely has me back to the drawing board to find a good way to handle debug logging. I'll figure out a cleaner / more reliable solution for that.
Apologies for all the questions but I just want to clarify -- what usage of static variables can cause undefined behavior with multiple plugin instances? For instance, right now I have a base class for representing an object in 3D space called GlObject, and all GlObjects share (as a member variable) a static reference to a GlCamera for grabbing view and perspective matrices since I wouldn't ever anticipate multiple cameras in a scene at once. GlCamera itself is a "regular" non-singleton class. Maybe I'm just pointing out another flaw in my design and should consider how to avoid that static reference to the camera, but are static variables safe to use anywhere? Is there a general rule for when they're safe to use, or should I avoid them altogether when writing code for a plugin?
I know I should eventually be sharing view and projection matrices via uniform buffer objects anyway, so the object / camera interface is due for a refactor regardless.
April 3, 2014
statics can get very complex to understand when dealing with libraries and in this situation they already may behave differently across platforms (aside what a standard may regulate in this area - truth is that I have seen those kind of issues). For example, consider a kind of shared base-library A, two libraries (B and C) which are independent from each other, but both utilize that base-library, and then your application/plugin library (D) which will use all three of these libraries. At what point will a static variable be initialized? Will B and C see the same static variable in A? Will D see the same instance of that static variable or will it have a different instance of it? Now the answer to this depends on a huge number of parameters like what platform/memory model/compiler do we have? What kind of variable is it ("plain old data" i.e. int/float/character/pointer or a "user defined" like class/struct) what linker options did you have, where is the variable defined (C-like as "extern" in a header, inside some function definition, in an anonymous namespace etc., compiler "hints" like volatile,register, mutable, __declspec etc) and most of all, is there static or dynamic linkage, and what is the runtime linkage, E.g. is it a delay-loaded, manual-loaded or implicitly loaded library? Do liberaries themselves link their dependencies or only the "main" library/application? Which of the libraries uses which other library in which of these modes? I'm sure that you will find a well defined behavior for each of the possible cases and "defined as undefined" behavior cases. The point about statics is - "it depends".
Ok, now to the design question. What's the point in making a camera static? And why at all should the "Object" know about the camera? The best advice I ever got regarding modeling is to think of the things as being real-world objects. So in reality, would your "objects" know about a camera that's watching them? Probably not! Can there only be one camera on earth? Why should it be a static member of GlObject then? I guess your design is resulting from the point where you needed to set the gl-transformation matrix from your object's draw/paint whateveryounamedit method? But consider this: in the real world - if someone is taking a picture of you with a camera - do YOU care about how you get "transformed" to the camera plane? Does the CAMERA care about it? The answer for you/the object clearly is NO. The camera only cares about the projection from 3D to 2D but not for its position in the scene! Making it a little shorter - lookup the concept of a "scene graph". The basic idea is keeping transformations and objects as separate entities where the transformations describe the spatial relations of the objects. The way to go would be to have set up the transformations already, before you enter the object's specific draw code. Another common thing is to pass the camera object into each draw-call of the GlObjects (or more generalized, pass some kind of "render state" which represents the GL-state and a part of it would be the current transformation). But talking about spatial hierarchy concepts for Computer Graphics may be a bit off-topic on the RackAFX forums, but if you want further help just let me know and I could contact you privately
About debug logging: If you don't need a "logging component" but only some channels for debug information, you may want to try this:
October 16, 2015
Tom, thanks for your thorough reply. I'll keep all that in mind with statics - I realize now how careful I will have to be with them if they are used at all. Unfortunately there have been a few cases where I've found no way around using statics... I wanted to set a non-static method as a callback function (from an external library) but couldn't find any way to properly do it without using a static method that then calls on an instance of the class I actually want to handle the callback. I believe I properly handled possible synchronization issues in the case of multiple plugin instances, but I'm still pretty new to threading and synchronization, and wouldn't be surprised if I didn't properly consider all the possibilities.
One possibility I've come to consider: would restricting the number of plugin instances to 1 be a bad practice? We never expect the user to want or need more than one instance of the plugin, and I believe enforcing that restriction would simplify some of the code. I don't quite know how I'd implement that restriction yet, but if it's unreasonable for some reason from a design perspective, I don't want to do the research to find out how it would be done.
Your mention of scene graphs got me to completely rethink and redesign my graphics code, I'm finally working on the implementation now after spending the past week or so working out the details. I'll definitely look at the debug logging link you sent as well.
And yes, apologies for posting graphics programming questions here! I know I'm getting off topic. The internet has provided some great resources for learning about scene graph implementation but I may still have questions every once and awhile that are more difficult to find answers for. If you'd be willing to exchange contacts, I'd really appreciate it! I don't know how we could do so through the forum though without publicly posting contact info - I don't see an option for us to PM each other.
Most Users Ever Online: 36
Currently Browsing this Page:
Guest Posters: 1
Newest Members:Matt, dspstudent, strings4v, TheSmile, semihyavuzz, alfredLue, danioc, midnightskate3, Alia5, Shamal Sundar
Moderators: W Pirkle: 208
Administrators: Tom: 67, JD Young: 80, Will Pirkle: 0, W Pirkle: 208