Browse Source

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
pull/17122/head
Max Katz 1 year ago
committed by GitHub
parent
commit
d7040e22d5
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 6
      build/TrimmingEnable.props
  2. 1
      src/Android/Avalonia.Android/Avalonia.Android.csproj
  3. 6
      src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs
  4. 6
      src/Android/Avalonia.Android/Platform/Vulkan/VulkanSupport.cs
  5. 1
      src/Avalonia.Base/Avalonia.Base.csproj
  6. 2
      src/Avalonia.Base/Media/Imaging/PixelFormatTranscoder.cs
  7. 27
      src/Avalonia.Base/Platform/Internal/UnmanagedBlob.cs
  8. 1
      src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj
  9. 1
      src/Avalonia.OpenGL/Avalonia.OpenGL.csproj
  10. 1
      src/Avalonia.Vulkan/Avalonia.Vulkan.csproj
  11. 1
      src/Avalonia.X11/Avalonia.X11.csproj
  12. 6
      src/Browser/Avalonia.Browser/Rendering/BrowserWebGlRenderTarget.cs
  13. 1
      src/Linux/Avalonia.LinuxFramebuffer/Avalonia.LinuxFramebuffer.csproj
  14. 20
      src/Skia/Avalonia.Skia/Gpu/Metal/SkiaMetalApi.cs
  15. 1
      src/Windows/Avalonia.Win32/Avalonia.Win32.csproj

6
build/TrimmingEnable.props

@ -19,4 +19,10 @@
<WarningsAsErrors Condition="'$(IsAotCompatible)' == 'true'">$(WarningsAsErrors);IL3050;IL3051;IL3052;IL3053;IL3054;IL3055;IL3056</WarningsAsErrors> <WarningsAsErrors Condition="'$(IsAotCompatible)' == 'true'">$(WarningsAsErrors);IL3050;IL3051;IL3052;IL3053;IL3054;IL3055;IL3056</WarningsAsErrors>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0')) AND '$(EnableRuntimeMarshalling)' != 'true'">
<WarningsAsErrors>$(WarningsAsErrors);CA1420;CA1421</WarningsAsErrors>
</PropertyGroup>
<ItemGroup Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0')) AND '$(EnableRuntimeMarshalling)' != 'true'">
<AssemblyAttribute Include="System.Runtime.CompilerServices.DisableRuntimeMarshallingAttribute" />
</ItemGroup>
</Project> </Project>

1
src/Android/Avalonia.Android/Avalonia.Android.csproj

@ -4,6 +4,7 @@
<SupportedOSPlatformVersion>$(AvsMinSupportedAndroidVersion)</SupportedOSPlatformVersion> <SupportedOSPlatformVersion>$(AvsMinSupportedAndroidVersion)</SupportedOSPlatformVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<AndroidResgenNamespace>Avalonia.Android.Internal</AndroidResgenNamespace> <AndroidResgenNamespace>Avalonia.Android.Internal</AndroidResgenNamespace>
<EnableRuntimeMarshalling>true</EnableRuntimeMarshalling>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\..\packages\Avalonia\Avalonia.csproj" /> <ProjectReference Include="..\..\..\packages\Avalonia\Avalonia.csproj" />

6
src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs

@ -6,7 +6,7 @@ using Avalonia.Platform;
namespace Avalonia.Android.Platform.SkiaPlatform namespace Avalonia.Android.Platform.SkiaPlatform
{ {
class AndroidFramebuffer : ILockedFramebuffer unsafe class AndroidFramebuffer : ILockedFramebuffer
{ {
private IntPtr _window; private IntPtr _window;
@ -24,7 +24,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
bottom = ANativeWindow_getHeight(_window) bottom = ANativeWindow_getHeight(_window)
}; };
Size = new PixelSize(rc.right, rc.bottom); 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 Format = buffer.format == AndroidPixelFormat.WINDOW_FORMAT_RGB_565
? PixelFormat.Rgb565 : PixelFormat.Rgba8888; ? PixelFormat.Rgb565 : PixelFormat.Rgba8888;
@ -61,7 +61,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
internal static extern void ANativeWindow_unlockAndPost(IntPtr window); internal static extern void ANativeWindow_unlockAndPost(IntPtr window);
[DllImport("android")] [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 public enum AndroidPixelFormat
{ {
WINDOW_FORMAT_RGBA_8888 = 1, WINDOW_FORMAT_RGBA_8888 = 1,

6
src/Android/Avalonia.Android/Platform/Vulkan/VulkanSupport.cs

@ -6,10 +6,10 @@ using Avalonia.Vulkan;
namespace Avalonia.Android.Platform.Vulkan namespace Avalonia.Android.Platform.Vulkan
{ {
internal class VulkanSupport internal partial class VulkanSupport
{ {
[DllImport("libvulkan.so")] [LibraryImport("libvulkan.so", StringMarshalling = StringMarshalling.Utf8)]
private static extern IntPtr vkGetInstanceProcAddr(IntPtr instance, string name); private static partial IntPtr vkGetInstanceProcAddr(IntPtr instance, string name);
public static VulkanPlatformGraphics? TryInitialize(VulkanOptions options) => public static VulkanPlatformGraphics? TryInitialize(VulkanOptions options) =>
VulkanPlatformGraphics.TryCreate(options ?? new(), new VulkanPlatformSpecificOptions VulkanPlatformGraphics.TryCreate(options ?? new(), new VulkanPlatformSpecificOptions

1
src/Avalonia.Base/Avalonia.Base.csproj

@ -5,7 +5,6 @@
<AllowUnsafeBlocks>True</AllowUnsafeBlocks> <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles> <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GeneratedFiles</CompilerGeneratedFilesOutputPath> <CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GeneratedFiles</CompilerGeneratedFilesOutputPath>
<IsTrimmable>true</IsTrimmable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="Assets\*.trie" /> <EmbeddedResource Include="Assets\*.trie" />

2
src/Avalonia.Base/Media/Imaging/PixelFormatTranscoder.cs

@ -18,7 +18,7 @@ internal static unsafe class PixelFormatTranscoder
AlphaFormat destAlphaFormat) AlphaFormat destAlphaFormat)
{ {
var pixelCount = srcSize.Width * srcSize.Height; var pixelCount = srcSize.Width * srcSize.Height;
var bufferSize = pixelCount * Marshal.SizeOf<Rgba8888Pixel>(); var bufferSize = pixelCount * sizeof(Rgba8888Pixel);
using var blob = new UnmanagedBlob(bufferSize); using var blob = new UnmanagedBlob(bufferSize);
var pixels = new Span<Rgba8888Pixel>((void*)blob.Address, pixelCount); var pixels = new Span<Rgba8888Pixel>((void*)blob.Address, pixelCount);

27
src/Avalonia.Base/Platform/Internal/UnmanagedBlob.cs

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading; using System.Threading;
using Avalonia.Compatibility;
namespace Avalonia.Platform.Internal; namespace Avalonia.Platform.Internal;
@ -108,21 +109,15 @@ internal class UnmanagedBlob : IDisposable
public int Size { get; private set; } public int Size { get; private set; }
public bool IsDisposed { 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); 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); 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. // Could be replaced with https://github.com/dotnet/runtime/issues/40892 when it will be available.
private IntPtr Alloc(int size) private IntPtr Alloc(int size)
{ {
if (!UseMmap) if (!OperatingSystemEx.IsLinux())
{ {
return Marshal.AllocHGlobal(size); 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); var rv = mmap(IntPtr.Zero, new IntPtr(size), 3, 0x22, -1, IntPtr.Zero);
if (rv.ToInt64() == -1 || (ulong)rv.ToInt64() == 0xffffffff) 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); throw new Exception("Unable to allocate memory: " + errno);
#else
throw new Exception("Unable to allocate memory");
#endif
} }
return rv; return rv;
} }
@ -140,7 +139,7 @@ internal class UnmanagedBlob : IDisposable
private void Free(IntPtr ptr, int len) private void Free(IntPtr ptr, int len)
{ {
if (!UseMmap) if (!OperatingSystemEx.IsLinux())
{ {
Marshal.FreeHGlobal(ptr); Marshal.FreeHGlobal(ptr);
} }
@ -148,8 +147,12 @@ internal class UnmanagedBlob : IDisposable
{ {
if (munmap(ptr, new IntPtr(len)) == -1) 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); throw new Exception("Unable to free memory: " + errno);
#else
throw new Exception("Unable to free memory");
#endif
} }
} }
} }

1
src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj

@ -3,6 +3,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>$(AvsCurrentTargetFramework);$(AvsLegacyTargetFrameworks);netstandard2.0</TargetFrameworks> <TargetFrameworks>$(AvsCurrentTargetFramework);$(AvsLegacyTargetFrameworks);netstandard2.0</TargetFrameworks>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<EnableRuntimeMarshalling>true</EnableRuntimeMarshalling>
</PropertyGroup> </PropertyGroup>
<Import Project="../../build/TrimmingEnable.props" /> <Import Project="../../build/TrimmingEnable.props" />

1
src/Avalonia.OpenGL/Avalonia.OpenGL.csproj

@ -3,6 +3,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>$(AvsCurrentTargetFramework);$(AvsLegacyTargetFrameworks);netstandard2.0</TargetFrameworks> <TargetFrameworks>$(AvsCurrentTargetFramework);$(AvsLegacyTargetFrameworks);netstandard2.0</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<EnableRuntimeMarshalling>true</EnableRuntimeMarshalling>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

1
src/Avalonia.Vulkan/Avalonia.Vulkan.csproj

@ -3,6 +3,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>$(AvsCurrentTargetFramework);$(AvsLegacyTargetFrameworks);netstandard2.0</TargetFrameworks> <TargetFrameworks>$(AvsCurrentTargetFramework);$(AvsLegacyTargetFrameworks);netstandard2.0</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<EnableRuntimeMarshalling>true</EnableRuntimeMarshalling>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

1
src/Avalonia.X11/Avalonia.X11.csproj

@ -2,6 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>$(AvsCurrentTargetFramework);$(AvsLegacyTargetFrameworks);netstandard2.0</TargetFrameworks> <TargetFrameworks>$(AvsCurrentTargetFramework);$(AvsLegacyTargetFrameworks);netstandard2.0</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<EnableRuntimeMarshalling>true</EnableRuntimeMarshalling>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

6
src/Browser/Avalonia.Browser/Rendering/BrowserWebGlRenderTarget.cs

@ -96,8 +96,8 @@ partial class WebGlContext : IGlContext, Avalonia.Skia.IGlSkiaSpecificOptionsFea
[JSImport("WebGlRenderTarget.makeContextCurrent", AvaloniaModule.MainModuleName)] [JSImport("WebGlRenderTarget.makeContextCurrent", AvaloniaModule.MainModuleName)]
private static partial bool MakeContextCurrent(int context); private static partial bool MakeContextCurrent(int context);
[DllImport("libSkiaSharp", EntryPoint = "eglGetProcAddress")] [LibraryImport("libSkiaSharp", EntryPoint = "eglGetProcAddress", StringMarshalling = StringMarshalling.Utf8)]
private static extern IntPtr eglGetProcAddress(string name); private static partial IntPtr eglGetProcAddress(string name);
private int _contextId; private int _contextId;
private readonly Thread _thread; private readonly Thread _thread;
@ -177,4 +177,4 @@ partial class WebGlContext : IGlContext, Avalonia.Skia.IGlSkiaSpecificOptionsFea
throw new NotSupportedException(); throw new NotSupportedException();
public bool UseNativeSkiaGrGlInterface => true; public bool UseNativeSkiaGrGlInterface => true;
} }

1
src/Linux/Avalonia.LinuxFramebuffer/Avalonia.LinuxFramebuffer.csproj

@ -2,6 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>$(AvsCurrentTargetFramework);$(AvsLegacyTargetFrameworks);netstandard2.0</TargetFrameworks> <TargetFrameworks>$(AvsCurrentTargetFramework);$(AvsLegacyTargetFrameworks);netstandard2.0</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<EnableRuntimeMarshalling>true</EnableRuntimeMarshalling>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\..\packages\Avalonia\Avalonia.csproj" /> <ProjectReference Include="..\..\..\packages\Avalonia\Avalonia.csproj" />

20
src/Skia/Avalonia.Skia/Gpu/Metal/SkiaMetalApi.cs

@ -1,6 +1,7 @@
using System; using System;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Avalonia.Compatibility; using Avalonia.Compatibility;
using Avalonia.Platform.Interop; using Avalonia.Platform.Interop;
@ -77,13 +78,18 @@ internal unsafe class SkiaMetalApi
{ {
options ??= new(); options ??= new();
var nativeOptions = _contextOptionsToNative.Invoke(options, null)!; var nativeOptions = _contextOptionsToNative.Invoke(options, null)!;
var pOptions = Marshal.AllocHGlobal(Marshal.SizeOf(nativeOptions)); var gcHandle = GCHandle.Alloc(nativeOptions, GCHandleType.Pinned);
Marshal.StructureToPtr(nativeOptions, pOptions, false); try
var context = _gr_direct_context_make_metal_with_options(device, queue, pOptions); {
Marshal.FreeHGlobal(pOptions); var context = _gr_direct_context_make_metal_with_options(device, queue, gcHandle.AddrOfPinnedObject());
if (context == IntPtr.Zero) if (context == IntPtr.Zero)
throw new InvalidOperationException("Unable to create GRContext from Metal device."); throw new InvalidOperationException("Unable to create GRContext from Metal device.");
return (GRContext)_contextCtor.Invoke(new object[] { context, true }); return (GRContext)_contextCtor.Invoke(new object[] { context, true });
}
finally
{
gcHandle.Free();
}
} }
internal struct GRMtlTextureInfoNative internal struct GRMtlTextureInfoNative

1
src/Windows/Avalonia.Win32/Avalonia.Win32.csproj

@ -2,6 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>$(AvsCurrentTargetFramework);$(AvsLegacyTargetFrameworks);netstandard2.0</TargetFrameworks> <TargetFrameworks>$(AvsCurrentTargetFramework);$(AvsLegacyTargetFrameworks);netstandard2.0</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<EnableRuntimeMarshalling>true</EnableRuntimeMarshalling>
<!-- We still keep BinaryFormatter for WinForms compatibility. --> <!-- We still keep BinaryFormatter for WinForms compatibility. -->
<EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization> <EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization>
</PropertyGroup> </PropertyGroup>

Loading…
Cancel
Save