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>
</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>

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

@ -4,6 +4,7 @@
<SupportedOSPlatformVersion>$(AvsMinSupportedAndroidVersion)</SupportedOSPlatformVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<AndroidResgenNamespace>Avalonia.Android.Internal</AndroidResgenNamespace>
<EnableRuntimeMarshalling>true</EnableRuntimeMarshalling>
</PropertyGroup>
<ItemGroup>
<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
{
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,

6
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

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

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

2
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<Rgba8888Pixel>();
var bufferSize = pixelCount * sizeof(Rgba8888Pixel);
using var blob = new UnmanagedBlob(bufferSize);
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.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
}
}
}

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

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

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

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

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

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

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

@ -2,6 +2,7 @@
<PropertyGroup>
<TargetFrameworks>$(AvsCurrentTargetFramework);$(AvsLegacyTargetFrameworks);netstandard2.0</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<EnableRuntimeMarshalling>true</EnableRuntimeMarshalling>
</PropertyGroup>
<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)]
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;
}
}

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

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

20
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

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

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

Loading…
Cancel
Save