mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-08 17:28:49 -10:00
OSX/MACOS: Plug MRR leaks in RetroArch_OSX ivar lifetimes
Follow-up to9743d1e. Audit of the other unretained id ivars in ui_cocoa.m surfaced three smaller lifetime bugs. Unlike the _sleepActivity crash they do not dangle - the referenced objects are kept alive by a second owner (NSWindow.contentView, the _listener delegate slot, g_instance) - so they manifest as leaks rather than EXC_BAD_ACCESS, but they are strictly incorrect under MRR and worth cleaning up while the area is warm. - _renderView: normalise the three -setViewType: paths to a +1 ownership invariant. [MetalView new] already hands us +1, so the Metal path is unchanged. The VULKAN and OPENGL paths get an explicit RARCH_RETAIN around [CocoaView get], which returns an unretained pointer to a singleton. The teardown block then gets a matching RARCH_RELEASE(_renderView) before nilling, so a view-type switch away from Metal no longer leaks the MetalView and switches between the singleton-based types no longer over-release. - CAMetalLayer: the VULKAN path was +alloc/+init-ing a layer and handing it to _renderView.layer (a strong reference, so the view took its own retain) without balancing our +1. Autorelease the local so the layer is freed once the view drops it. - _listener (HAVE_COCOA_METAL only): created with +new (+1) in -applicationDidFinishLaunching: and wired up as the window's delegate and nextResponder - both of which are non-retaining relationships, so the ivar was the sole owner. Release it in -dealloc (MRR branch) so the listener is not leaked at shutdown. No behavioural change under ARC, where strong ivars already track these retains automatically and the RARCH_RETAIN / RARCH_RELEASE macros expand to no-ops. The pre-10.9 SDK compatibility guard stays scoped to the App Nap code path from9743d1e- none of the APIs touched here are version-sensitive.
This commit is contained in:
1 parent
9743d1e1c3
commit
e9279a82db
1 file changed
+31
-2
+31
-2
@@ -630,6 +630,17 @@ static ui_application_t ui_application_cocoa = {
|
||||
[pi endActivity:token];
|
||||
RARCH_RELEASE(token);
|
||||
}
|
||||
#endif
|
||||
/* _renderView is kept at +1 by setViewType:; release the balance
|
||||
* here so the last view-type's render view does not leak at
|
||||
* shutdown. Safe when nil. */
|
||||
RARCH_RELEASE(_renderView);
|
||||
#ifdef HAVE_COCOA_METAL
|
||||
/* _listener was created with +new (+1) in applicationDidFinishLaunching:
|
||||
* and installed as the window's delegate / nextResponder, which are
|
||||
* unretained relationships. Release our own retain so the listener
|
||||
* does not leak at shutdown. */
|
||||
RARCH_RELEASE(_listener);
|
||||
#endif
|
||||
RARCH_RELEASE(_window);
|
||||
RARCH_SUPER_DEALLOC();
|
||||
@@ -719,6 +730,13 @@ static ui_application_t ui_application_cocoa = {
|
||||
_renderView.layer = nil;
|
||||
[_renderView removeFromSuperview];
|
||||
self.window.contentView = nil;
|
||||
/* _renderView holds a +1 retain regardless of which path created
|
||||
* it below (see the RARCH_RETAIN on the [CocoaView get] paths,
|
||||
* and the inherent +1 from +new on the Metal path). Release it
|
||||
* here so the ownership invariant is balanced before we nil the
|
||||
* ivar. Under ARC this is a no-op and the implicit __strong
|
||||
* ivar handles the release when _renderView is assigned nil. */
|
||||
RARCH_RELEASE(_renderView);
|
||||
_renderView = nil;
|
||||
}
|
||||
|
||||
@@ -726,17 +744,27 @@ static ui_application_t ui_application_cocoa = {
|
||||
{
|
||||
case APPLE_VIEW_TYPE_VULKAN:
|
||||
{
|
||||
_renderView = [CocoaView get];
|
||||
/* [CocoaView get] returns an unretained pointer to a
|
||||
* singleton. Retain explicitly so _renderView's +1
|
||||
* ownership invariant matches the Metal path below. */
|
||||
_renderView = RARCH_RETAIN([CocoaView get]);
|
||||
CAMetalLayer *metal_layer = [[CAMetalLayer alloc] init];
|
||||
metal_layer.device = MTLCreateSystemDefaultDevice();
|
||||
metal_layer.framebufferOnly = YES;
|
||||
metal_layer.contentsScale = [[NSScreen mainScreen] backingScaleFactor];
|
||||
/* CALayer.layer is a strong reference, so the view takes
|
||||
* its own retain. Autorelease our +1 from +alloc/+init
|
||||
* so we don't leak the layer on every view-type switch. */
|
||||
_renderView.layer = metal_layer;
|
||||
RARCH_AUTORELEASE(metal_layer);
|
||||
[_renderView setWantsLayer:YES];
|
||||
}
|
||||
break;
|
||||
case APPLE_VIEW_TYPE_METAL:
|
||||
{
|
||||
/* +new returns a +1 object; that retain transfers into
|
||||
* _renderView and satisfies the ivar's ownership
|
||||
* invariant directly. No extra RARCH_RETAIN needed. */
|
||||
MetalView *v = [MetalView new];
|
||||
v.paused = YES;
|
||||
v.enableSetNeedsDisplay = NO;
|
||||
@@ -744,7 +772,8 @@ static ui_application_t ui_application_cocoa = {
|
||||
}
|
||||
break;
|
||||
case APPLE_VIEW_TYPE_OPENGL:
|
||||
_renderView = [CocoaView get];
|
||||
/* Same singleton-retain story as the VULKAN case. */
|
||||
_renderView = RARCH_RETAIN([CocoaView get]);
|
||||
break;
|
||||
case APPLE_VIEW_TYPE_NONE:
|
||||
default:
|
||||
|
||||
Reference in new issue
Block a user