That's effectively true with the global allocators already, in the
sense that setting one set of allocators in one part of the application, and later a different set of allocators in another part is unlikely to end well
This is a really good point, and is the main reason I want to come up with something better. I have one last idea, and it's something I do for FNA every now and then: A formalized extension.
In this case it would be something like "CustomAllocatorEXT", where all the construction entry points get a new overload like "FAudioCreateWithCustomAllocatorEXT", which is the same as the official FAudioCreate but with added parameters for function pointer types like FAudioCustomMallocEXT, and those would get stored in each context. The nice thing about everything being tied together in an extension is that I can document in big giant letters "DO NOT MIX ALLOCATORS" and avoid both the global variable safety issue as well as the malloc/free mismatch problems.
It also avoids possible breakage of the existing APIs, which is something we now have to consider as of FNA 18.10's release. I've been pretty lenient with breakages in the past for stuff like MojoShader and Theorafile since those are used by pretty much nobody but myself and Ryan, and even for the small FNA community that's managed to pop up on occasion.
-Ethan
On 10/19/18 22:42, Henri Verbeet wrote:
On Sat, 20 Oct 2018 at 04:35, Ethan Lee flibitijibibo@flibitijibibo.com wrote:
The biggest problem is that there are _loads_ of entry points that aren't necessarily coupled with one another - the main ones are XAudio2Create, XACT3CreateEngine, CreateReverb, CreateVolumeMeter, and CreateFX, all of which are technically supposed to be decoupled from one another even though they all directly interact with each other and nothing outside of this subsystem of DirectX. The famous "we're totally decoupled except for the part where we're not" scenario. So in reality, you're not setting 1 allocator, you're setting up to 5:
Personally, I don't have an issue with that. I.e., I think providing allocators to each entry point that needs them would be fine.
You might be thinking we could add the callback system to every function, but keep in mind that the allocators in some parts should be the same as in others, or malloc/free mismatches can occur. Admittedly it's "some" and not "all", but the fact that it's ambiguous is what makes it kind of dangerous to wield (IMO). Even worse, there's situations like AudioEngine_Initialize that takes in an optional XAudio2 parameter:
https://github.com/FNA-XNA/FAudio/blob/2fdfc193940a1aa9a89f84ce46bf7ff84280a...
So then some questions come up along the lines of "which allocator do we use, the XACT3 allocator all the time, or the XAudio2 allocator if we provide that (since the engine may have already allocated some stuff), or do we allow an XACT3 with allocator A and a custom XAudio2 with allocator B, and try to support both at the same time," and that's just the interaction between XACT and XAudio; there are potential conflicts with XAPO as well because the APO could be using allocator A but XAudio expects allocator B when reading RegistrationProprties, and that's not factoring in what could happen with custom XAudio2 voices you can set on XACT3 voices with custom XAPOs attached... you get the idea.
The global allocator definitely feels primitive and clunky, but I don't know if I have it in me to figure out the above...
Yeah, you'd have to resolve that somehow. Ideally that would mean carefully thinking about which kinds of interactions make sense, but the easy way out would be to define it away by saying something along the lines of "Using objects created with incompatible allocators together results in undefined behaviour". That's effectively true with the global allocators already, in the sense that setting one set of allocators in one part of the application, and later a different set of allocators in another part is unlikely to end well; where it makes a difference is for objects that don't interact.
In practice, I'd expect Wine to always use the same allocators, so the argument is perhaps somewhat academic. From an API-design point of view though, it seems better to try to get it right the first time than to have to fix it later.