From 5828203f8e2b3bb5b36f7483a1050669930cc80d Mon Sep 17 00:00:00 2001 From: Jarl Gullberg Date: Fri, 23 Jun 2017 14:37:11 +0200 Subject: [PATCH 1/7] Implemented an autorelease pool for Cocoa's NativeWindow implementation. --- src/OpenTK/Platform/MacOS/CocoaNativeWindow.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/OpenTK/Platform/MacOS/CocoaNativeWindow.cs b/src/OpenTK/Platform/MacOS/CocoaNativeWindow.cs index 72ae5c00..9dad0c9e 100644 --- a/src/OpenTK/Platform/MacOS/CocoaNativeWindow.cs +++ b/src/OpenTK/Platform/MacOS/CocoaNativeWindow.cs @@ -137,6 +137,7 @@ namespace OpenTK.Platform.MacOS } private CocoaWindowInfo windowInfo; + private IntPtr autoreleasePool; private IntPtr windowClass; private IntPtr trackingArea; private IntPtr current_icon_handle; @@ -157,6 +158,10 @@ namespace OpenTK.Platform.MacOS public CocoaNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device) { + // Create a new autorelease pool for allocations in this window (mach ports, etc) + autoreleasePool = Cocoa.SendIntPtr(Class.NSAutoreleasePool, Selector.Get("alloc")); + autoreleasePool = Cocoa.SendIntPtr(autoreleasePool, Selector.Get("init")); + // Create callback methods. We need to store those, // otherwise the GC may collect them while they are // still active. @@ -1283,6 +1288,9 @@ namespace OpenTK.Platform.MacOS Debug.Print("[Mac] Disposing {0}", windowInfo); windowInfo.Dispose(); + + // Drain the autorelease pool for the application, closing mach ports + Cocoa.SendVoid(autoreleasePool, Selector.Get("drain")); } else { From a7ddb543a94ed973cfcf681c6dc134994003968e Mon Sep 17 00:00:00 2001 From: Jarl Gullberg Date: Thu, 29 Jun 2017 12:43:19 +0200 Subject: [PATCH 2/7] Moved the autorelease pool to the context. --- src/OpenTK/Platform/MacOS/CocoaContext.cs | 12 ++++++++++++ src/OpenTK/Platform/MacOS/CocoaNativeWindow.cs | 9 +-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/OpenTK/Platform/MacOS/CocoaContext.cs b/src/OpenTK/Platform/MacOS/CocoaContext.cs index 485713fa..79958f63 100644 --- a/src/OpenTK/Platform/MacOS/CocoaContext.cs +++ b/src/OpenTK/Platform/MacOS/CocoaContext.cs @@ -54,6 +54,8 @@ namespace OpenTK "/System/Library/Frameworks/OpenGL.framework/OpenGLES", AddImageFlags.ReturnOnError); + private IntPtr autoreleasePool; + static CocoaContext() { Cocoa.Initialize(); @@ -117,6 +119,10 @@ namespace OpenTK private void CreateContext(GraphicsMode mode, CocoaWindowInfo cocoaWindow, IntPtr shareContextRef, int majorVersion, int minorVersion, bool fullscreen) { + // Create a new autorelease pool for allocations in this context (mach ports, etc) + autoreleasePool = Cocoa.SendIntPtr(Class.NSAutoreleasePool, Selector.Get("alloc")); + autoreleasePool = Cocoa.SendIntPtr(autoreleasePool, Selector.Get("init")); + // Prepare attributes IntPtr pixelFormat = SelectPixelFormat(mode, majorVersion, minorVersion); if (pixelFormat == IntPtr.Zero) @@ -352,6 +358,12 @@ namespace OpenTK Cocoa.SendVoid(Handle.Handle, Selector.Get("clearDrawable")); Cocoa.SendVoid(Handle.Handle, Selector.Get("release")); + // Drain the autorelease pool for the context, closing mach ports (if there is one) + if (autoreleasePool != IntPtr.Zero) + { + Cocoa.SendVoid(autoreleasePool, Selector.Get("drain")); + } + Handle = ContextHandle.Zero; IsDisposed = true; diff --git a/src/OpenTK/Platform/MacOS/CocoaNativeWindow.cs b/src/OpenTK/Platform/MacOS/CocoaNativeWindow.cs index 9dad0c9e..5ec5fe93 100644 --- a/src/OpenTK/Platform/MacOS/CocoaNativeWindow.cs +++ b/src/OpenTK/Platform/MacOS/CocoaNativeWindow.cs @@ -137,7 +137,7 @@ namespace OpenTK.Platform.MacOS } private CocoaWindowInfo windowInfo; - private IntPtr autoreleasePool; + private IntPtr windowClass; private IntPtr trackingArea; private IntPtr current_icon_handle; @@ -158,10 +158,6 @@ namespace OpenTK.Platform.MacOS public CocoaNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device) { - // Create a new autorelease pool for allocations in this window (mach ports, etc) - autoreleasePool = Cocoa.SendIntPtr(Class.NSAutoreleasePool, Selector.Get("alloc")); - autoreleasePool = Cocoa.SendIntPtr(autoreleasePool, Selector.Get("init")); - // Create callback methods. We need to store those, // otherwise the GC may collect them while they are // still active. @@ -1288,9 +1284,6 @@ namespace OpenTK.Platform.MacOS Debug.Print("[Mac] Disposing {0}", windowInfo); windowInfo.Dispose(); - - // Drain the autorelease pool for the application, closing mach ports - Cocoa.SendVoid(autoreleasePool, Selector.Get("drain")); } else { From 3cf07ff790d752411d96b7ceac6d9c3dbd967a83 Mon Sep 17 00:00:00 2001 From: Jarl Gullberg Date: Sun, 9 Jul 2017 23:13:32 +0200 Subject: [PATCH 3/7] Broke the autorelease code out into a class and replaced the usage. --- src/OpenTK/OpenTK.csproj | 1 + .../Platform/MacOS/Cocoa/NSAutoreleasePool.cs | 34 +++++++++++++++++++ src/OpenTK/Platform/MacOS/CocoaContext.cs | 22 +++--------- 3 files changed, 40 insertions(+), 17 deletions(-) create mode 100644 src/OpenTK/Platform/MacOS/Cocoa/NSAutoreleasePool.cs diff --git a/src/OpenTK/OpenTK.csproj b/src/OpenTK/OpenTK.csproj index 93e68005..bf4af5e4 100644 --- a/src/OpenTK/OpenTK.csproj +++ b/src/OpenTK/OpenTK.csproj @@ -137,6 +137,7 @@ + diff --git a/src/OpenTK/Platform/MacOS/Cocoa/NSAutoreleasePool.cs b/src/OpenTK/Platform/MacOS/Cocoa/NSAutoreleasePool.cs new file mode 100644 index 00000000..5e7e3ee0 --- /dev/null +++ b/src/OpenTK/Platform/MacOS/Cocoa/NSAutoreleasePool.cs @@ -0,0 +1,34 @@ +using System; + +namespace OpenTK.Platform.MacOS +{ + /// + /// The class is a wrapper around the native objective-C NSAutoreleasePool. + /// In particular, this construct mimics the usage of an @autorelease block and can be used in much the same way, + /// only with a C# using block instead. + /// + public sealed class NSAutoreleasePool : IDisposable + { + private readonly IntPtr _autoreleasePool; + + /// + /// Allocates and initializes a new . + /// + public NSAutoreleasePool() + { + _autoreleasePool = Cocoa.SendIntPtr(Class.NSAutoreleasePool, Selector.Get("alloc")); + _autoreleasePool = Cocoa.SendIntPtr(_autoreleasePool, Selector.Get("init")); + } + + /// + /// Disposes of the instance, draining it. + /// + public void Dispose() + { + if (_autoreleasePool != IntPtr.Zero) + { + Cocoa.SendVoid(_autoreleasePool, Selector.Get("drain")); + } + } + } +} \ No newline at end of file diff --git a/src/OpenTK/Platform/MacOS/CocoaContext.cs b/src/OpenTK/Platform/MacOS/CocoaContext.cs index 79958f63..850cd109 100644 --- a/src/OpenTK/Platform/MacOS/CocoaContext.cs +++ b/src/OpenTK/Platform/MacOS/CocoaContext.cs @@ -54,8 +54,6 @@ namespace OpenTK "/System/Library/Frameworks/OpenGL.framework/OpenGLES", AddImageFlags.ReturnOnError); - private IntPtr autoreleasePool; - static CocoaContext() { Cocoa.Initialize(); @@ -119,10 +117,6 @@ namespace OpenTK private void CreateContext(GraphicsMode mode, CocoaWindowInfo cocoaWindow, IntPtr shareContextRef, int majorVersion, int minorVersion, bool fullscreen) { - // Create a new autorelease pool for allocations in this context (mach ports, etc) - autoreleasePool = Cocoa.SendIntPtr(Class.NSAutoreleasePool, Selector.Get("alloc")); - autoreleasePool = Cocoa.SendIntPtr(autoreleasePool, Selector.Get("init")); - // Prepare attributes IntPtr pixelFormat = SelectPixelFormat(mode, majorVersion, minorVersion); if (pixelFormat == IntPtr.Zero) @@ -346,22 +340,16 @@ namespace OpenTK Debug.Print("Disposing of Cocoa context."); - if (!NSApplication.IsUIThread) - { - return; - } + using (var pool = new NSAutoreleasePool()) + {if (!NSApplication.IsUIThread) + { return;} if (IsCurrent) - { - Cocoa.SendVoid(NSOpenGLContext, Selector.Get("clearCurrentContext")); - } + { Cocoa.SendVoid(NSOpenGLContext, Selector.Get("clearCurrentContext"));} Cocoa.SendVoid(Handle.Handle, Selector.Get("clearDrawable")); Cocoa.SendVoid(Handle.Handle, Selector.Get("release")); - // Drain the autorelease pool for the context, closing mach ports (if there is one) - if (autoreleasePool != IntPtr.Zero) - { - Cocoa.SendVoid(autoreleasePool, Selector.Get("drain")); + } Handle = ContextHandle.Zero; From af1e3bdf0f7f318660553e3632513166c5571c4b Mon Sep 17 00:00:00 2001 From: Jarl Gullberg Date: Fri, 4 Aug 2017 17:41:45 +0200 Subject: [PATCH 4/7] Correct screwy formatting. --- src/OpenTK/Platform/MacOS/CocoaContext.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/OpenTK/Platform/MacOS/CocoaContext.cs b/src/OpenTK/Platform/MacOS/CocoaContext.cs index 850cd109..67b68cb1 100644 --- a/src/OpenTK/Platform/MacOS/CocoaContext.cs +++ b/src/OpenTK/Platform/MacOS/CocoaContext.cs @@ -341,15 +341,21 @@ namespace OpenTK Debug.Print("Disposing of Cocoa context."); using (var pool = new NSAutoreleasePool()) - {if (!NSApplication.IsUIThread) - { return;} + { + if (!NSApplication.IsUIThread) + { + return; - if (IsCurrent) - { Cocoa.SendVoid(NSOpenGLContext, Selector.Get("clearCurrentContext"));} - Cocoa.SendVoid(Handle.Handle, Selector.Get("clearDrawable")); - Cocoa.SendVoid(Handle.Handle, Selector.Get("release")); + } + if (IsCurrent) + { + Cocoa.SendVoid(NSOpenGLContext, Selector.Get("clearCurrentContext")); + } + + Cocoa.SendVoid(Handle.Handle, Selector.Get("clearDrawable")); + Cocoa.SendVoid(Handle.Handle, Selector.Get("release")); } Handle = ContextHandle.Zero; From c02e959f7a70a5f45d59fec924e6db5eaed658a3 Mon Sep 17 00:00:00 2001 From: Jarl Gullberg Date: Fri, 4 Aug 2017 18:39:44 +0200 Subject: [PATCH 5/7] Move early return out of the autorelease pool. --- src/OpenTK/Platform/MacOS/CocoaContext.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/OpenTK/Platform/MacOS/CocoaContext.cs b/src/OpenTK/Platform/MacOS/CocoaContext.cs index 67b68cb1..eaae8324 100644 --- a/src/OpenTK/Platform/MacOS/CocoaContext.cs +++ b/src/OpenTK/Platform/MacOS/CocoaContext.cs @@ -340,18 +340,16 @@ namespace OpenTK Debug.Print("Disposing of Cocoa context."); + if (!NSApplication.IsUIThread) + { + return; + } + using (var pool = new NSAutoreleasePool()) { - if (!NSApplication.IsUIThread) - { - return; - - } - if (IsCurrent) { Cocoa.SendVoid(NSOpenGLContext, Selector.Get("clearCurrentContext")); - } Cocoa.SendVoid(Handle.Handle, Selector.Get("clearDrawable")); From b0e7465f6cf3abcbb4055e155e2732e48bc454a1 Mon Sep 17 00:00:00 2001 From: Jarl Gullberg Date: Fri, 4 Aug 2017 18:40:16 +0200 Subject: [PATCH 6/7] Reuse selectors. --- src/OpenTK/Platform/MacOS/Cocoa/NSAutoreleasePool.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/OpenTK/Platform/MacOS/Cocoa/NSAutoreleasePool.cs b/src/OpenTK/Platform/MacOS/Cocoa/NSAutoreleasePool.cs index 5e7e3ee0..074e65a8 100644 --- a/src/OpenTK/Platform/MacOS/Cocoa/NSAutoreleasePool.cs +++ b/src/OpenTK/Platform/MacOS/Cocoa/NSAutoreleasePool.cs @@ -16,8 +16,8 @@ namespace OpenTK.Platform.MacOS /// public NSAutoreleasePool() { - _autoreleasePool = Cocoa.SendIntPtr(Class.NSAutoreleasePool, Selector.Get("alloc")); - _autoreleasePool = Cocoa.SendIntPtr(_autoreleasePool, Selector.Get("init")); + _autoreleasePool = Cocoa.SendIntPtr(Class.NSAutoreleasePool, Selector.Alloc); + _autoreleasePool = Cocoa.SendIntPtr(_autoreleasePool, Selector.Init); } /// From 77bca92a02d1e063fa77caf4c6a40c620d865472 Mon Sep 17 00:00:00 2001 From: Jarl Gullberg Date: Fri, 4 Aug 2017 18:46:17 +0200 Subject: [PATCH 7/7] Use local variable instead of reusing the field. --- src/OpenTK/Platform/MacOS/Cocoa/NSAutoreleasePool.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/OpenTK/Platform/MacOS/Cocoa/NSAutoreleasePool.cs b/src/OpenTK/Platform/MacOS/Cocoa/NSAutoreleasePool.cs index 074e65a8..e6ba6c42 100644 --- a/src/OpenTK/Platform/MacOS/Cocoa/NSAutoreleasePool.cs +++ b/src/OpenTK/Platform/MacOS/Cocoa/NSAutoreleasePool.cs @@ -16,8 +16,8 @@ namespace OpenTK.Platform.MacOS /// public NSAutoreleasePool() { - _autoreleasePool = Cocoa.SendIntPtr(Class.NSAutoreleasePool, Selector.Alloc); - _autoreleasePool = Cocoa.SendIntPtr(_autoreleasePool, Selector.Init); + var uninitializedPool = Cocoa.SendIntPtr(Class.NSAutoreleasePool, Selector.Alloc); + _autoreleasePool = Cocoa.SendIntPtr(uninitializedPool, Selector.Init); } ///