Skip to content

Commit 8d2f620

Browse files
authored
Merge pull request #6495 from frenzibyte/fix-macos-texture-release
Fix incorrect release pattern in macOS/iOS texture loading code
2 parents b27e4fb + 82272ae commit 8d2f620

13 files changed

+72
-51
lines changed

osu.Framework.iOS/Graphics/Textures/IOSTextureLoaderStore.cs

+12-9
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,21 @@ public IOSTextureLoaderStore(IResourceStore<byte[]> store)
2020

2121
protected override unsafe Image<TPixel> ImageFromStream<TPixel>(Stream stream)
2222
{
23-
int length = (int)(stream.Length - stream.Position);
24-
using var nativeData = NSMutableData.FromLength(length);
23+
using (new NSAutoreleasePool())
24+
{
25+
int length = (int)(stream.Length - stream.Position);
26+
var nativeData = NSMutableData.FromLength(length);
2527

26-
var bytesSpan = new Span<byte>(nativeData.MutableBytes.ToPointer(), length);
27-
stream.ReadExactly(bytesSpan);
28+
var bytesSpan = new Span<byte>(nativeData.MutableBytes.ToPointer(), length);
29+
stream.ReadExactly(bytesSpan);
2830

29-
using var uiImage = UIImage.LoadFromData(nativeData);
30-
if (uiImage == null)
31-
throw new ArgumentException($"{nameof(Image)} could not be created from {nameof(stream)}.");
31+
using var uiImage = UIImage.LoadFromData(nativeData);
32+
if (uiImage == null)
33+
throw new ArgumentException($"{nameof(Image)} could not be created from {nameof(stream)}.");
3234

33-
var cgImage = new Platform.Apple.Native.CGImage(uiImage.CGImage!.Handle);
34-
return ImageFromCGImage<TPixel>(cgImage);
35+
var cgImage = new Platform.Apple.Native.CGImage(uiImage.CGImage!.Handle);
36+
return ImageFromCGImage<TPixel>(cgImage);
37+
}
3538
}
3639
}
3740
}

osu.Framework/Platform/Apple/Native/Class.cs

-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
using System;
55
using System.Runtime.InteropServices;
6-
using osu.Framework.Platform.MacOS.Native;
76

87
namespace osu.Framework.Platform.Apple.Native
98
{

osu.Framework/Platform/Apple/Native/NSArray.cs

-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// See the LICENCE file in the repository root for full licence text.
33

44
using System;
5-
using osu.Framework.Platform.MacOS.Native;
65

76
namespace osu.Framework.Platform.Apple.Native
87
{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
2+
// See the LICENCE file in the repository root for full licence text.
3+
4+
using System;
5+
6+
namespace osu.Framework.Platform.Apple.Native
7+
{
8+
internal readonly struct NSAutoreleasePool : IDisposable
9+
{
10+
internal IntPtr Handle { get; }
11+
12+
internal NSAutoreleasePool(IntPtr handle)
13+
{
14+
Handle = handle;
15+
}
16+
17+
private static readonly IntPtr class_pointer = Class.Get("NSAutoreleasePool");
18+
private static readonly IntPtr sel_alloc = Selector.Get("alloc");
19+
private static readonly IntPtr sel_init = Selector.Get("init");
20+
private static readonly IntPtr sel_drain = Selector.Get("drain");
21+
22+
public static NSAutoreleasePool Init()
23+
{
24+
var pool = alloc();
25+
Interop.SendIntPtr(pool.Handle, sel_init);
26+
return pool;
27+
}
28+
29+
private static NSAutoreleasePool alloc() => new NSAutoreleasePool(Interop.SendIntPtr(class_pointer, sel_alloc));
30+
31+
public void Dispose()
32+
{
33+
if (Handle != IntPtr.Zero)
34+
Interop.SendIntPtr(Handle, sel_drain);
35+
}
36+
}
37+
}

osu.Framework/Platform/Apple/Native/NSData.cs

+1-11
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,14 @@
33

44
using System;
55
using System.Runtime.InteropServices;
6-
using osu.Framework.Platform.MacOS.Native;
76

87
namespace osu.Framework.Platform.Apple.Native
98
{
10-
internal readonly struct NSData : IDisposable
9+
internal readonly struct NSData
1110
{
1211
internal IntPtr Handle { get; }
1312

1413
private static readonly IntPtr class_pointer = Class.Get("NSData");
15-
private static readonly IntPtr sel_release = Selector.Get("release");
1614
private static readonly IntPtr sel_data_with_bytes = Selector.Get("dataWithBytes:length:");
1715
private static readonly IntPtr sel_bytes = Selector.Get("bytes");
1816
private static readonly IntPtr sel_length = Selector.Get("length");
@@ -34,14 +32,6 @@ internal byte[] ToBytes()
3432
return bytes;
3533
}
3634

37-
internal void Release() => Interop.SendVoid(Handle, sel_release);
38-
39-
public void Dispose()
40-
{
41-
if (Handle != IntPtr.Zero)
42-
Release();
43-
}
44-
4535
internal static unsafe NSData FromBytes(ReadOnlySpan<byte> bytes)
4636
{
4737
fixed (byte* ptr = bytes)

osu.Framework/Platform/Apple/Native/NSMutableData.cs

+1-11
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,14 @@
22
// See the LICENCE file in the repository root for full licence text.
33

44
using System;
5-
using osu.Framework.Platform.MacOS.Native;
65

76
namespace osu.Framework.Platform.Apple.Native
87
{
9-
internal readonly struct NSMutableData : IDisposable
8+
internal readonly struct NSMutableData
109
{
1110
internal IntPtr Handle { get; }
1211

1312
private static readonly IntPtr class_pointer = Class.Get("NSMutableData");
14-
private static readonly IntPtr sel_release = Selector.Get("release");
1513
private static readonly IntPtr sel_data_with_length = Selector.Get("dataWithLength:");
1614
private static readonly IntPtr sel_mutable_bytes = Selector.Get("mutableBytes");
1715

@@ -22,14 +20,6 @@ internal NSMutableData(IntPtr handle)
2220

2321
internal unsafe byte* MutableBytes => (byte*)Interop.SendIntPtr(Handle, sel_mutable_bytes);
2422

25-
internal void Release() => Interop.SendVoid(Handle, sel_release);
26-
27-
public void Dispose()
28-
{
29-
if (Handle != IntPtr.Zero)
30-
Release();
31-
}
32-
3323
internal static NSMutableData FromLength(int length)
3424
{
3525
IntPtr handle = Interop.SendIntPtr(class_pointer, sel_data_with_length, length);

osu.Framework/Platform/Apple/Native/NSNotificationCenter.cs

-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// See the LICENCE file in the repository root for full licence text.
33

44
using System;
5-
using osu.Framework.Platform.MacOS.Native;
65

76
namespace osu.Framework.Platform.Apple.Native
87
{

osu.Framework/Platform/Apple/Native/NSString.cs

-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
using System;
55
using System.Runtime.InteropServices;
6-
using osu.Framework.Platform.MacOS.Native;
76

87
namespace osu.Framework.Platform.Apple.Native
98
{

osu.Framework/Platform/MacOS/Native/Selector.cs renamed to osu.Framework/Platform/Apple/Native/Selector.cs

+1-2
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@
33

44
using System;
55
using System.Runtime.InteropServices;
6-
using osu.Framework.Platform.Apple.Native;
76

8-
namespace osu.Framework.Platform.MacOS.Native
7+
namespace osu.Framework.Platform.Apple.Native
98
{
109
internal static partial class Selector
1110
{

osu.Framework/Platform/MacOS/MacOSClipboard.cs

+6-3
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,12 @@ public override bool SetImage(Image image)
3535
using var stream = new MemoryStream();
3636
image.SaveAsTiff(stream);
3737

38-
using var nsData = NSData.FromBytes(stream.ToArray());
39-
using var nsImage = NSImage.LoadFromData(nsData);
40-
return setToPasteboard(nsImage.Handle);
38+
using (NSAutoreleasePool.Init())
39+
{
40+
var nsData = NSData.FromBytes(stream.ToArray());
41+
using var nsImage = NSImage.LoadFromData(nsData);
42+
return setToPasteboard(nsImage.Handle);
43+
}
4144
}
4245

4346
private IntPtr getFromPasteboard(IntPtr @class)

osu.Framework/Platform/MacOS/MacOSTextureLoaderStore.cs

+12-9
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,21 @@ public MacOSTextureLoaderStore(IResourceStore<byte[]> store)
2020

2121
protected override unsafe Image<TPixel> ImageFromStream<TPixel>(Stream stream)
2222
{
23-
int length = (int)(stream.Length - stream.Position);
24-
using var nativeData = NSMutableData.FromLength(length);
23+
using (NSAutoreleasePool.Init())
24+
{
25+
int length = (int)(stream.Length - stream.Position);
26+
var nativeData = NSMutableData.FromLength(length);
2527

26-
var bytesSpan = new Span<byte>(nativeData.MutableBytes, length);
27-
stream.ReadExactly(bytesSpan);
28+
var bytesSpan = new Span<byte>(nativeData.MutableBytes, length);
29+
stream.ReadExactly(bytesSpan);
2830

29-
using var nsImage = NSImage.LoadFromData(nativeData);
30-
if (nsImage.Handle == IntPtr.Zero)
31-
throw new ArgumentException($"{nameof(Image)} could not be created from {nameof(stream)}.");
31+
using var nsImage = NSImage.LoadFromData(nativeData);
32+
if (nsImage.Handle == IntPtr.Zero)
33+
throw new ArgumentException($"{nameof(Image)} could not be created from {nameof(stream)}.");
3234

33-
var cgImage = nsImage.CGImage;
34-
return ImageFromCGImage<TPixel>(cgImage);
35+
var cgImage = nsImage.CGImage;
36+
return ImageFromCGImage<TPixel>(cgImage);
37+
}
3538
}
3639
}
3740
}

osu.Framework/Platform/MacOS/SDL2MacOSWindow.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55

66
using System;
77
using osu.Framework.Platform.Apple.Native;
8-
using osu.Framework.Platform.MacOS.Native;
98
using osu.Framework.Platform.SDL2;
109
using osuTK;
10+
using Selector = osu.Framework.Platform.Apple.Native.Selector;
1111

1212
namespace osu.Framework.Platform.MacOS
1313
{

osu.Framework/Platform/MacOS/SDL3MacOSWindow.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55

66
using System;
77
using osu.Framework.Platform.Apple.Native;
8-
using osu.Framework.Platform.MacOS.Native;
98
using osu.Framework.Platform.SDL3;
109
using osuTK;
10+
using Selector = osu.Framework.Platform.Apple.Native.Selector;
1111

1212
namespace osu.Framework.Platform.MacOS
1313
{

0 commit comments

Comments
 (0)