Browse Source

add vulkan support for android (#15588)

pull/15594/head
Emmanuel Hansen 2 years ago
committed by GitHub
parent
commit
cffc23a0c6
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 16
      src/Android/Avalonia.Android/AndroidPlatform.cs
  2. 4
      src/Android/Avalonia.Android/Avalonia.Android.csproj
  3. 25
      src/Android/Avalonia.Android/Platform/Vulkan/VulkanNativeInterop.cs
  4. 68
      src/Android/Avalonia.Android/Platform/Vulkan/VulkanSupport.cs
  5. 1
      src/Windows/Avalonia.Win32/Win32PlatformOptions.cs

16
src/Android/Avalonia.Android/AndroidPlatform.cs

@ -4,6 +4,7 @@ using System.Linq;
using Avalonia.Android;
using Avalonia.Android.Platform;
using Avalonia.Android.Platform.Input;
using Avalonia.Android.Platform.Vulkan;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Input;
using Avalonia.Input.Platform;
@ -11,6 +12,7 @@ using Avalonia.OpenGL.Egl;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Rendering.Composition;
using Avalonia.Vulkan;
namespace Avalonia
{
@ -38,7 +40,12 @@ namespace Avalonia
/// <summary>
/// Enables android EGL rendering.
/// </summary>
Egl = 2
Egl = 2,
/// <summary>
/// Enables Vulkan rendering
/// </summary>
Vulkan = 3
}
public sealed class AndroidPlatformOptions
@ -114,6 +121,13 @@ namespace Avalonia.Android
return egl;
}
}
if (renderingMode == AndroidRenderingMode.Vulkan)
{
var vulkan = VulkanSupport.TryInitialize(AvaloniaLocator.Current.GetService<VulkanOptions>() ?? new());
if (vulkan != null)
return vulkan;
}
}
throw new InvalidOperationException($"{nameof(AndroidPlatformOptions)}.{nameof(AndroidPlatformOptions.RenderingMode)} has a value of \"{string.Join(", ", opts.RenderingMode)}\", but no options were applied.");

4
src/Android/Avalonia.Android/Avalonia.Android.csproj

@ -17,4 +17,8 @@
<Import Project="..\..\..\build\DevAnalyzers.props" />
<Import Project="..\..\..\build\TrimmingEnable.props" />
<Import Project="..\..\..\build\NullableEnable.props" />
<Import Project="..\..\..\build\SourceGenerators.props" />
<ItemGroup>
<Compile Remove="..\..\Shared\SourceGeneratorAttributes.cs" />
</ItemGroup>
</Project>

25
src/Android/Avalonia.Android/Platform/Vulkan/VulkanNativeInterop.cs

@ -0,0 +1,25 @@
using System;
using Avalonia.SourceGenerator;
using Avalonia.Vulkan;
namespace Avalonia.Android.Platform.Vulkan;
partial class AndroidVulkanInterface
{
public AndroidVulkanInterface(IVulkanInstance instance)
{
Initialize(name => instance.GetInstanceProcAddress(instance.Handle, name));
}
[GetProcAddress("vkCreateAndroidSurfaceKHR")]
public partial int vkCreateAndroidSurfaceKHR(IntPtr instance, ref VkAndroidSurfaceCreateInfoKHR pCreateInfo,
IntPtr pAllocator, out ulong pSurface);
}
struct VkAndroidSurfaceCreateInfoKHR
{
public const uint VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR = 1000008000;
public uint sType;
public IntPtr pNext;
public uint flags;
public IntPtr window;
}

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

@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Avalonia.Platform;
using Avalonia.Vulkan;
namespace Avalonia.Android.Platform.Vulkan
{
internal class VulkanSupport
{
[DllImport("libvulkan.so")]
private static extern IntPtr vkGetInstanceProcAddr(IntPtr instance, string name);
public static VulkanPlatformGraphics? TryInitialize(VulkanOptions options) =>
VulkanPlatformGraphics.TryCreate(options ?? new(), new VulkanPlatformSpecificOptions
{
RequiredInstanceExtensions = { "VK_KHR_android_surface" },
GetProcAddressDelegate = vkGetInstanceProcAddr,
PlatformFeatures = new Dictionary<Type, object>
{
[typeof(IVulkanKhrSurfacePlatformSurfaceFactory)] = new VulkanSurfaceFactory()
}
});
internal class VulkanSurfaceFactory : IVulkanKhrSurfacePlatformSurfaceFactory
{
public bool CanRenderToSurface(IVulkanPlatformGraphicsContext context, object surface) =>
surface is INativePlatformHandleSurface handle;
public IVulkanKhrSurfacePlatformSurface CreateSurface(IVulkanPlatformGraphicsContext context, object handle) =>
new AndroidVulkanSurface((INativePlatformHandleSurface)handle);
}
class AndroidVulkanSurface : IVulkanKhrSurfacePlatformSurface
{
private INativePlatformHandleSurface _handle;
public AndroidVulkanSurface(INativePlatformHandleSurface handle)
{
_handle = handle;
}
public double Scaling => _handle.Scaling;
public PixelSize Size => _handle.Size;
public ulong CreateSurface(IVulkanPlatformGraphicsContext context) =>
CreateAndroidSurface(_handle.Handle, context.Instance);
public void Dispose()
{
// No-op
}
}
private static ulong CreateAndroidSurface(nint handle, IVulkanInstance instance)
{
var vulkanAndroid = new AndroidVulkanInterface(instance);
var createInfo = new VkAndroidSurfaceCreateInfoKHR()
{
sType = VkAndroidSurfaceCreateInfoKHR.VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR,
window = handle
};
VulkanException.ThrowOnError("vkCreateAndroidSurfaceKHR",
vulkanAndroid.vkCreateAndroidSurfaceKHR(instance.Handle, ref createInfo, IntPtr.Zero, out var surface));
return surface;
}
}
}

1
src/Windows/Avalonia.Win32/Win32PlatformOptions.cs

@ -23,6 +23,7 @@ public enum Win32RenderingMode
/// Avalonia would try to use native Widows OpenGL with GPU rendering.
/// </summary>
Wgl = 3,
/// <summary>
/// Avalonia would try to use native Widows Vulkan with GPU rendering.
/// </summary>

Loading…
Cancel
Save