8 ms·
The c++ wrappings break ARC, so if you use this library you'll have to manually retain/release any object. The autorelease pool is helpful if you autorelease an
by ash_gti 5y ago
The c++ wrappings break ARC, so if you use this library you'll have to manually retain/release any object. The autorelease pool is helpful if you autorelease an object but you'll need to manually manage the memory when using this set of helpers.
In obj-c or swift, ARC would handle that for you, so this makes the memory management aspect of using Metal a bit more of a headache.
- comex 5y agoHuh, I'm surprised. I had just assumed without looking that this library provided wrapper classes where the copy constructor calls retain and the destructor calls release. Apparently not.
- lukeh 5y agoYeah, kind of weird there's no smart ARC class, although I suppose you need a way to override it when you need a weak reference. I guess it would be trivial to add one?
- arcticbull 5y agoShould be pretty trivial to create RAII Obj-C variants of shared_ptr and unique_ptr that automatically call retain and release as the reference is acquired, and when it leaves scope, respectively. It doesn't break ARC right, it just won't do the automatic reference counting in C++ source. You can send it back and forth over the wall with CFBridgingRetain and CFBridgingRelease no? Having an autorelease pool is pretty standard practice, and ARC works the same way in ObjC (and I assume Swift) apps - stuff that was autoreleased accumulates in the pool until it is drained, which tends to happen every turn of the run loop.
- ash_gti 5y ago> It doesn't break ARC right, it just won't do the automatic reference counting in C++ source. You can send it back and forth over the wall with CFBridgingRetain and CFBridgingRelease no? I guess I should say that clang's ARC doesn't apply to these c++ wrappers. The c++ code is loading symbols using the objc runtime API's to load symbols and call objc runtime APIs to dispatch the metal calls. So, you could pass these references to other objc code and it should have the correct refcounts afterwards. Having to manually retain/release objects is a bit of a pain, but its workable. Using a c++ RAII type to retain/release is also somewhat do-able, but I worked in a codebase that had that kind of code and it can be frustrating to get the refcounts to be correct synchronized. Although that was back with c++11, so I'm sure things have changed that would make this easier today.
- arcticbull 5y agoThanks for the follow-up!
- raphlinus 5y agoRight. Would you happen to know if there's a way to make a retained object actually deallocate on last "release," other than putting an autorelease pool around it? Would you also happen to know if the Swift bindings have this same wonky autorelease behavior, or more straightforward Swift-style refcounting?
- comex 5y agoFrom a quick grep, it looks like this wrapper does not automatically call autorelease, so autorelease happens only when a method implementation autoreleases its own return value (or if you call autorelease yourself). Objective-C has a standard rule for when a method is supposed to autorelease its return value: to quote the metal-cpp readme, it's when "you create an object with a method that does not begin with `alloc`, `new`, `copy`, or `mutableCopy`". In many cases, these are convenience methods that also have equivalent "initWith" methods, e.g. [NSString stringWithFormat:@"%d", 42] is equivalent to [[[NSString alloc] initWithFormat:@"%d", 42] autorelease] But I'm not too familiar with Metal, and… it looks like Metal doesn't have very many of these methods in the first place. Instead it has a lot of 'new' methods, which shouldn't use autorelease. When a method does call autorelease, Swift doesn't have any way of getting around it, though if there are autoreleasing and alloc/init variants of the same method, it will prefer alloc/init. Other than that, Swift likes to use the function objc_retainAutoreleasedReturnValue [1], which may prevent the object from going on the autorelease pool (with the 'optimized return' magic), but only as a non-guaranteed optimization. [1] https://github.com/apple-opensource/objc4/blob/a367941bce42b1515aeb2cc17020c65e3a57fa20/runtime/NSObject.mm#L2158 https://github.com/apple-opensource/objc4/blob/a367941bce42b...
- raphlinus 5y agoThanks, this is helpful. The specific method that's causing me trouble right at the moment is "computeCommandEncoder"[1], which is a method off MTLCommandBuffer, and I think not in the "new" class. In the Rust bindings[2], this is just a msg_send! and from what I can tell is getting an autoreleased reference, not a retained one. It looks like objc_retainAutoreleasedReturnValue might be exactly what I'm looking for, even if it isn't 100% guaranteed; if I'm understanding, it would be safe, and wouldn't actually leak as long as you had an autorelease pool somewhere in the chain. However, I'm not seeing a binding to it in the objc crate[3]. Sounds like maybe I should file an issue? Also, given that such a method seems obviously useful, I wonder why it's not being called from these C++ bindings? [1]: https://developer.apple.com/documentation/metal/mtlcommandbuffer/1443044-computecommandencoder?language=objc https://developer.apple.com/documentation/metal/mtlcommandbu... [2]: https://github.com/gfx-rs/metal-rs/blob/master/src/commandbuffer.rs#L105 https://github.com/gfx-rs/metal-rs/blob/master/src/commandbu... [3]: https://docs.rs/objc/0.2.7/objc/runtime/index.html https://docs.rs/objc/0.2.7/objc/runtime/index.html