Skip to content

Commit

Permalink
add vulkan support for android (#15588)
Browse files Browse the repository at this point in the history
  • Loading branch information
emmauss authored and maxkatz6 committed May 8, 2024
1 parent 7990b4b commit 3246934
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 1 deletion.
16 changes: 15 additions & 1 deletion src/Android/Avalonia.Android/AndroidPlatform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
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;
using Avalonia.OpenGL.Egl;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Rendering.Composition;
using Avalonia.Vulkan;

namespace Avalonia
{
Expand Down Expand Up @@ -38,7 +40,12 @@ public enum AndroidRenderingMode
/// <summary>
/// Enables android EGL rendering.
/// </summary>
Egl = 2
Egl = 2,

/// <summary>
/// Enables Vulkan rendering
/// </summary>
Vulkan = 3
}

public sealed class AndroidPlatformOptions
Expand Down Expand Up @@ -114,6 +121,13 @@ public static void Initialize()
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.");
Expand Down
4 changes: 4 additions & 0 deletions src/Android/Avalonia.Android/Avalonia.Android.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Original file line number Diff line number Diff line change
@@ -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 changes: 68 additions & 0 deletions src/Android/Avalonia.Android/Platform/Vulkan/VulkanSupport.cs
Original file line number Diff line number Diff line change
@@ -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 change: 1 addition & 0 deletions src/Windows/Avalonia.Win32/Win32PlatformOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down

0 comments on commit 3246934

Please sign in to comment.