From d7040e22d50fa2747fdf7533bdf5c532ee9ed47b Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 25 Sep 2024 03:48:25 -0700 Subject: [PATCH] Begin with DisableRuntimeMarshalling support + fix macOS Metal AOT (#17116) * Add attribute * Replace `SetLastError = true` with `Marshal.GetLastSystemError()` * Make Avalonia.Base and Avalonia.Skia compatible with DisableRuntimeMarshalling * First step in Android DisableRuntimeMarshalling support * Make Avalonia.Browser compatible * Set EnableRuntimeMarshalling=true on all projects we are not yet ready to support without runtime marshalling --- build/TrimmingEnable.props | 6 +++++ .../Avalonia.Android/Avalonia.Android.csproj | 1 + .../SkiaPlatform/AndroidFramebuffer.cs | 6 ++--- .../Platform/Vulkan/VulkanSupport.cs | 6 ++--- src/Avalonia.Base/Avalonia.Base.csproj | 1 - .../Media/Imaging/PixelFormatTranscoder.cs | 2 +- .../Platform/Internal/UnmanagedBlob.cs | 27 ++++++++++--------- .../Avalonia.FreeDesktop.csproj | 1 + src/Avalonia.OpenGL/Avalonia.OpenGL.csproj | 1 + src/Avalonia.Vulkan/Avalonia.Vulkan.csproj | 1 + src/Avalonia.X11/Avalonia.X11.csproj | 1 + .../Rendering/BrowserWebGlRenderTarget.cs | 6 ++--- .../Avalonia.LinuxFramebuffer.csproj | 1 + .../Avalonia.Skia/Gpu/Metal/SkiaMetalApi.cs | 20 +++++++++----- .../Avalonia.Win32/Avalonia.Win32.csproj | 1 + 15 files changed, 51 insertions(+), 30 deletions(-) diff --git a/build/TrimmingEnable.props b/build/TrimmingEnable.props index 1fa14cb022..34b3e232b6 100644 --- a/build/TrimmingEnable.props +++ b/build/TrimmingEnable.props @@ -19,4 +19,10 @@ $(WarningsAsErrors);IL3050;IL3051;IL3052;IL3053;IL3054;IL3055;IL3056 + + $(WarningsAsErrors);CA1420;CA1421 + + + + diff --git a/src/Android/Avalonia.Android/Avalonia.Android.csproj b/src/Android/Avalonia.Android/Avalonia.Android.csproj index 170cc088fb..236422885a 100644 --- a/src/Android/Avalonia.Android/Avalonia.Android.csproj +++ b/src/Android/Avalonia.Android/Avalonia.Android.csproj @@ -4,6 +4,7 @@ $(AvsMinSupportedAndroidVersion) true Avalonia.Android.Internal + true diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs index 94e5f4bd01..20361b113b 100644 --- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs +++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs @@ -6,7 +6,7 @@ using Avalonia.Platform; namespace Avalonia.Android.Platform.SkiaPlatform { - class AndroidFramebuffer : ILockedFramebuffer + unsafe class AndroidFramebuffer : ILockedFramebuffer { private IntPtr _window; @@ -24,7 +24,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform bottom = ANativeWindow_getHeight(_window) }; Size = new PixelSize(rc.right, rc.bottom); - ANativeWindow_lock(_window, out buffer, ref rc); + ANativeWindow_lock(_window, &buffer, &rc); Format = buffer.format == AndroidPixelFormat.WINDOW_FORMAT_RGB_565 ? PixelFormat.Rgb565 : PixelFormat.Rgba8888; @@ -61,7 +61,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform internal static extern void ANativeWindow_unlockAndPost(IntPtr window); [DllImport("android")] - internal static extern int ANativeWindow_lock(IntPtr window, out ANativeWindow_Buffer outBuffer, ref ARect inOutDirtyBounds); + internal static extern int ANativeWindow_lock(IntPtr window, ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds); public enum AndroidPixelFormat { WINDOW_FORMAT_RGBA_8888 = 1, diff --git a/src/Android/Avalonia.Android/Platform/Vulkan/VulkanSupport.cs b/src/Android/Avalonia.Android/Platform/Vulkan/VulkanSupport.cs index 86f9f5938e..5d1b0e309a 100644 --- a/src/Android/Avalonia.Android/Platform/Vulkan/VulkanSupport.cs +++ b/src/Android/Avalonia.Android/Platform/Vulkan/VulkanSupport.cs @@ -6,10 +6,10 @@ using Avalonia.Vulkan; namespace Avalonia.Android.Platform.Vulkan { - internal class VulkanSupport + internal partial class VulkanSupport { - [DllImport("libvulkan.so")] - private static extern IntPtr vkGetInstanceProcAddr(IntPtr instance, string name); + [LibraryImport("libvulkan.so", StringMarshalling = StringMarshalling.Utf8)] + private static partial IntPtr vkGetInstanceProcAddr(IntPtr instance, string name); public static VulkanPlatformGraphics? TryInitialize(VulkanOptions options) => VulkanPlatformGraphics.TryCreate(options ?? new(), new VulkanPlatformSpecificOptions diff --git a/src/Avalonia.Base/Avalonia.Base.csproj b/src/Avalonia.Base/Avalonia.Base.csproj index 15f0665fd0..ce2d9ce9bc 100644 --- a/src/Avalonia.Base/Avalonia.Base.csproj +++ b/src/Avalonia.Base/Avalonia.Base.csproj @@ -5,7 +5,6 @@ True true $(BaseIntermediateOutputPath)\GeneratedFiles - true diff --git a/src/Avalonia.Base/Media/Imaging/PixelFormatTranscoder.cs b/src/Avalonia.Base/Media/Imaging/PixelFormatTranscoder.cs index 6659197e1a..8cd0d5ca77 100644 --- a/src/Avalonia.Base/Media/Imaging/PixelFormatTranscoder.cs +++ b/src/Avalonia.Base/Media/Imaging/PixelFormatTranscoder.cs @@ -18,7 +18,7 @@ internal static unsafe class PixelFormatTranscoder AlphaFormat destAlphaFormat) { var pixelCount = srcSize.Width * srcSize.Height; - var bufferSize = pixelCount * Marshal.SizeOf(); + var bufferSize = pixelCount * sizeof(Rgba8888Pixel); using var blob = new UnmanagedBlob(bufferSize); var pixels = new Span((void*)blob.Address, pixelCount); diff --git a/src/Avalonia.Base/Platform/Internal/UnmanagedBlob.cs b/src/Avalonia.Base/Platform/Internal/UnmanagedBlob.cs index 9a7582ca5f..eeba160a3c 100644 --- a/src/Avalonia.Base/Platform/Internal/UnmanagedBlob.cs +++ b/src/Avalonia.Base/Platform/Internal/UnmanagedBlob.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; +using Avalonia.Compatibility; namespace Avalonia.Platform.Internal; @@ -108,21 +109,15 @@ internal class UnmanagedBlob : IDisposable public int Size { get; private set; } public bool IsDisposed { get; private set; } - [DllImport("libc", SetLastError = true)] + [DllImport("libc")] private static extern IntPtr mmap(IntPtr addr, IntPtr length, int prot, int flags, int fd, IntPtr offset); - [DllImport("libc", SetLastError = true)] + [DllImport("libc")] private static extern int munmap(IntPtr addr, IntPtr length); - [DllImport("libc", SetLastError = true)] - private static extern long sysconf(int name); - - private bool? _useMmap; - private bool UseMmap - => _useMmap ?? ((_useMmap = RuntimeInformation.IsOSPlatform(OSPlatform.Linux)).Value); // Could be replaced with https://github.com/dotnet/runtime/issues/40892 when it will be available. private IntPtr Alloc(int size) { - if (!UseMmap) + if (!OperatingSystemEx.IsLinux()) { return Marshal.AllocHGlobal(size); } @@ -131,8 +126,12 @@ internal class UnmanagedBlob : IDisposable var rv = mmap(IntPtr.Zero, new IntPtr(size), 3, 0x22, -1, IntPtr.Zero); if (rv.ToInt64() == -1 || (ulong)rv.ToInt64() == 0xffffffff) { - var errno = Marshal.GetLastWin32Error(); +#if NET6_0_OR_GREATER + var errno = Marshal.GetLastSystemError(); throw new Exception("Unable to allocate memory: " + errno); +#else + throw new Exception("Unable to allocate memory"); +#endif } return rv; } @@ -140,7 +139,7 @@ internal class UnmanagedBlob : IDisposable private void Free(IntPtr ptr, int len) { - if (!UseMmap) + if (!OperatingSystemEx.IsLinux()) { Marshal.FreeHGlobal(ptr); } @@ -148,8 +147,12 @@ internal class UnmanagedBlob : IDisposable { if (munmap(ptr, new IntPtr(len)) == -1) { - var errno = Marshal.GetLastWin32Error(); +#if NET6_0_OR_GREATER + var errno = Marshal.GetLastSystemError(); throw new Exception("Unable to free memory: " + errno); +#else + throw new Exception("Unable to free memory"); +#endif } } } diff --git a/src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj b/src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj index 0cb0f04bc2..5dc19e593e 100644 --- a/src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj +++ b/src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj @@ -3,6 +3,7 @@ $(AvsCurrentTargetFramework);$(AvsLegacyTargetFrameworks);netstandard2.0 enable + true diff --git a/src/Avalonia.OpenGL/Avalonia.OpenGL.csproj b/src/Avalonia.OpenGL/Avalonia.OpenGL.csproj index e6a4e2724b..2c5734ed45 100644 --- a/src/Avalonia.OpenGL/Avalonia.OpenGL.csproj +++ b/src/Avalonia.OpenGL/Avalonia.OpenGL.csproj @@ -3,6 +3,7 @@ $(AvsCurrentTargetFramework);$(AvsLegacyTargetFrameworks);netstandard2.0 true + true diff --git a/src/Avalonia.Vulkan/Avalonia.Vulkan.csproj b/src/Avalonia.Vulkan/Avalonia.Vulkan.csproj index 59b8e62708..e270d64d70 100644 --- a/src/Avalonia.Vulkan/Avalonia.Vulkan.csproj +++ b/src/Avalonia.Vulkan/Avalonia.Vulkan.csproj @@ -3,6 +3,7 @@ $(AvsCurrentTargetFramework);$(AvsLegacyTargetFrameworks);netstandard2.0 true + true diff --git a/src/Avalonia.X11/Avalonia.X11.csproj b/src/Avalonia.X11/Avalonia.X11.csproj index 67a81ad154..b09bea889f 100644 --- a/src/Avalonia.X11/Avalonia.X11.csproj +++ b/src/Avalonia.X11/Avalonia.X11.csproj @@ -2,6 +2,7 @@ $(AvsCurrentTargetFramework);$(AvsLegacyTargetFrameworks);netstandard2.0 true + true diff --git a/src/Browser/Avalonia.Browser/Rendering/BrowserWebGlRenderTarget.cs b/src/Browser/Avalonia.Browser/Rendering/BrowserWebGlRenderTarget.cs index bbb713255b..db66c9a0ee 100644 --- a/src/Browser/Avalonia.Browser/Rendering/BrowserWebGlRenderTarget.cs +++ b/src/Browser/Avalonia.Browser/Rendering/BrowserWebGlRenderTarget.cs @@ -96,8 +96,8 @@ partial class WebGlContext : IGlContext, Avalonia.Skia.IGlSkiaSpecificOptionsFea [JSImport("WebGlRenderTarget.makeContextCurrent", AvaloniaModule.MainModuleName)] private static partial bool MakeContextCurrent(int context); - [DllImport("libSkiaSharp", EntryPoint = "eglGetProcAddress")] - private static extern IntPtr eglGetProcAddress(string name); + [LibraryImport("libSkiaSharp", EntryPoint = "eglGetProcAddress", StringMarshalling = StringMarshalling.Utf8)] + private static partial IntPtr eglGetProcAddress(string name); private int _contextId; private readonly Thread _thread; @@ -177,4 +177,4 @@ partial class WebGlContext : IGlContext, Avalonia.Skia.IGlSkiaSpecificOptionsFea throw new NotSupportedException(); public bool UseNativeSkiaGrGlInterface => true; -} \ No newline at end of file +} diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Avalonia.LinuxFramebuffer.csproj b/src/Linux/Avalonia.LinuxFramebuffer/Avalonia.LinuxFramebuffer.csproj index f4a2948c48..444eb13875 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/Avalonia.LinuxFramebuffer.csproj +++ b/src/Linux/Avalonia.LinuxFramebuffer/Avalonia.LinuxFramebuffer.csproj @@ -2,6 +2,7 @@ $(AvsCurrentTargetFramework);$(AvsLegacyTargetFrameworks);netstandard2.0 true + true diff --git a/src/Skia/Avalonia.Skia/Gpu/Metal/SkiaMetalApi.cs b/src/Skia/Avalonia.Skia/Gpu/Metal/SkiaMetalApi.cs index 2085e065ee..d5e2352e13 100644 --- a/src/Skia/Avalonia.Skia/Gpu/Metal/SkiaMetalApi.cs +++ b/src/Skia/Avalonia.Skia/Gpu/Metal/SkiaMetalApi.cs @@ -1,6 +1,7 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Reflection; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Avalonia.Compatibility; using Avalonia.Platform.Interop; @@ -77,13 +78,18 @@ internal unsafe class SkiaMetalApi { options ??= new(); var nativeOptions = _contextOptionsToNative.Invoke(options, null)!; - var pOptions = Marshal.AllocHGlobal(Marshal.SizeOf(nativeOptions)); - Marshal.StructureToPtr(nativeOptions, pOptions, false); - var context = _gr_direct_context_make_metal_with_options(device, queue, pOptions); - Marshal.FreeHGlobal(pOptions); - if (context == IntPtr.Zero) - throw new InvalidOperationException("Unable to create GRContext from Metal device."); - return (GRContext)_contextCtor.Invoke(new object[] { context, true }); + var gcHandle = GCHandle.Alloc(nativeOptions, GCHandleType.Pinned); + try + { + var context = _gr_direct_context_make_metal_with_options(device, queue, gcHandle.AddrOfPinnedObject()); + if (context == IntPtr.Zero) + throw new InvalidOperationException("Unable to create GRContext from Metal device."); + return (GRContext)_contextCtor.Invoke(new object[] { context, true }); + } + finally + { + gcHandle.Free(); + } } internal struct GRMtlTextureInfoNative diff --git a/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj b/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj index b924ceebc3..c299bcba4e 100644 --- a/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj +++ b/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj @@ -2,6 +2,7 @@ $(AvsCurrentTargetFramework);$(AvsLegacyTargetFrameworks);netstandard2.0 true + true true