Skip to content

Instantly share code, notes, and snippets.

@attilaz
Created November 26, 2016 18:45
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save attilaz/d75fc7d4ab75388a42720f97a7075c81 to your computer and use it in GitHub Desktop.
Save attilaz/d75fc7d4ab75388a42720f97a7075c81 to your computer and use it in GitHub Desktop.
metal transient object lifetime
From metal documentation:
"Command buffer and command encoder objects are transient and designed for a single use.
They are very inexpensive to allocate and deallocate, so their creation methods return autoreleased objects."
https://developer.apple.com/library/content/documentation/Miscellaneous/Conceptual/MetalProgrammingGuide/Cmd-Submiss/Cmd-Submiss.html
Autorelease example:
NSAutoreleasePool* autoreleasePool = [[NSAutoreleasePool alloc] init];
//c is an autoreleased object
SampleClass* c = [[SampleClass alloc] init];//refcount is 1
[c autorelease]; //refcount is 1 (1 for pool)
[autoreleasePool release]; //pool is released it calls release on every object it is added to.
//c's refcount will be 0, so it will be deallocated
Autorelease example 2:
NSAutoreleasePool* autoreleasePool = [[NSAutoreleasePool alloc] init];
SampleClass* c = [[SampleClass alloc] init];//refcount is 1
[c retain]; //refcount is 2
[c autorelease]; //refcount is 2 (1 for pool)
[autoreleasePool release]; //when pool is released it calls release on every object it is added to.
//c's refcount will be 1, so it won't be deallocated
[c release]; //c's refcount will be 0, it is dealloced
In the examples for iOS there is an autoreleasepool now:
https://github.com/bkaradzic/bgfx/blob/master/examples/common/entry/entry_ios.mm#L366
but there is no autoreleasepool on OSX.
A simple thing like this leaks on OSX but works perfectly on iOS now:
SampleClass* c = [[SampleClass alloc] init];//refcount is 1
[c autorelease]; //refcount is 1 (1 for pool)
So a "m_commandBuffer = m_commandQueue.commandBuffer();" will release the object when the autoreleasepool is finished.
But on OSX it won't be released.
On iOS the autoreleasepool is finished at the end of the frame. This causes a problem when flipping is at the beginning of
the frame (https://github.com/bkaradzic/bgfx/blob/master/src/bgfx.cpp#L1580) because when the flip command is called
every transient object would be already deallocated.
frameX:
autoreleasepool begin
...
setRenderTarget(Drawable_for_frameX)
...
autoreleasepool end //Drawable_for_frameX is released here
frameX+1:
autoreleasepool begin
...
presentDrawable(Drawable_for_frameX) //error
...
autoreleasebool end
So we have to use manual refcount handling because of these like this
(https://github.com/bkaradzic/bgfx/blob/master/src/renderer_mtl.mm#L820).
The recent memleak is because even rendercommander encoders are transient and leaked on OSX.
I think we should use a method that works similarly on iOS and OSX to avoid these:
https://github.com/bkaradzic/bgfx/commit/dbe4c52d8f56648ee5d5d1144d19accbb4efe8c3
https://github.com/bkaradzic/bgfx/commit/413972736fc60a61e1346378f2d91422546bd111#diff-816a76ffbf9c1e03ccfcc65d248f8369R1735
"It is highly advisable to contain your rendering loop within an autorelease pool block to avoid possible deadlock
situations with multiple drawables."
https://developer.apple.com/library/content/documentation/3DDrawing/Conceptual/MTLBestPracticesGuide/Drawables.html
If we use manual release of objects it will be error-prone because on iOS there is always an autoreleasepool and if we
skip a manual retain/release it will work on fine on iOS and crash/leak on OSX.
So I think we should add an autoreleasepool in OSX too.
Without the need the ability to flip at the beginning of the frame we could get rid of lots of
manual retains/releases and use simply an autorelease pool. I don't think it is worth to keep this ability.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment