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.