DX10 Buffer resource reference counting

· by Steve · Read in about 3 min · (571 Words)

As most of you will know, Direct X has always used the COM reference counting mechanism. Personally I’ve always hated the explicit reference counting style (ie having to call Release() when you are finished with an object) - because of the negative effects of not calling Release the precisely correct number of times it’s not really far removed from having to manually manage memory anyway, and is vastly inferior to the automatic reference counting done by smarter systems such as boost:shared_ptr<> (which Ogre uses a derivation of, natch). Of course, the reason for their choice is that they wanted to support pure C applications as well as C++, although to my mind this is such an ancient historical reason they should by now be assuming C++ and providing nasty fallbacks for the few people using vanilla C, not architecting around old styles and making C++ developers' lives more difficult. Then again, they’re rather more focussed on .Net these days anyway.

Anyhow, the crux of this post was some uncertainty about how asynchronous buffer copies work because of this explicit model. Copying data from one buffer to another via CopyResource et al is (thankfully) asynchronous, allowing us to sidestep pipeline stalls. All well and good, but I have a need to for example fill a temporary staging buffer (locked / mapped on the CPU) and then queue a copy of the data to the GPU buffer resource. I want to ‘fire and forget’ this, meaning that there is likely to be cases where I want to free the temporary staging buffer afterwards. Now obviously it shouldn’t be freed until after the async copy is done, but my CPU code isn’t keeping track of when this happens. The natural solution is reference counting - I should free my local reference after queueing the copy, and once the copy operation is done, it should free its own reference and the staging resource would be deleted.

Had resource counting been ‘built in’ to Dx10 structures like shared_ptr, this would just be a given - merely copying the shared_ptr via the formal arguments would guarantee a reference count increment going into the function and for the duration any copy of it was held for the asynchronous implementation. But because reference counting is manual, I’m left wondering whether calling CopyResource will in fact increment the reference count on the buffer (via AddRef), and whether the completion of this asynchronous task will end up calling Release() afterwards, as required. If it doesn’t, then if I call Release() after CopyResource I’ll end up freeing the buffer before the async copy happens, which will be nasty driver-side crashville. The Dx10 docs are completely silent on this issue as far as I can tell. This is one of the reasons I detest manual reference counting - you need explicit documentation about how reference counts are updated internally by API calls which just isn’t an issue in automatic systems. Grr.

Anyone happen to know whether CopyResource calls AddRef on the passed in pointers and Release afterwards? Or do I have to have some kind of dumb cleanup operation at some indeterminate time later once the async copy has actually completed? Common sense suggests AddRef / Release must be called internally by CopyResource and its async implementation, but I’m rather loathe to assume here and I have a ton more work to do before I can start smoke testing this kind of thing.