1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using Silk.NET.Core;
using Silk.NET.Vulkan;
using Silk.NET.Vulkan.Extensions.EXT;
namespace Ryujinx.Ava.Ui.Vulkan
{
public class VulkanInstance : IDisposable
{
private const string EngineName = "Avalonia Vulkan";
private VulkanInstance(Instance apiHandle, Vk api)
{
InternalHandle = apiHandle;
Api = api;
}
public IntPtr Handle => InternalHandle.Handle;
internal Instance InternalHandle { get; }
public Vk Api { get; }
internal static IEnumerable<string> RequiredInstanceExtensions
{
get
{
yield return "VK_KHR_surface";
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
yield return "VK_KHR_xlib_surface";
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
yield return "VK_KHR_win32_surface";
}
}
}
public void Dispose()
{
Api?.DestroyInstance(InternalHandle, Span<AllocationCallbacks>.Empty);
Api?.Dispose();
}
internal static unsafe VulkanInstance Create(VulkanOptions options)
{
var api = Vk.GetApi();
var applicationName = Marshal.StringToHGlobalAnsi(options.ApplicationName);
var engineName = Marshal.StringToHGlobalAnsi(EngineName);
var enabledExtensions = new List<string>(options.InstanceExtensions);
enabledExtensions.AddRange(RequiredInstanceExtensions);
var applicationInfo = new ApplicationInfo
{
PApplicationName = (byte*)applicationName,
ApiVersion = new Version32((uint)options.VulkanVersion.Major, (uint)options.VulkanVersion.Minor,
(uint)options.VulkanVersion.Build),
PEngineName = (byte*)engineName,
EngineVersion = new Version32(1, 0, 0),
ApplicationVersion = new Version32(1, 0, 0)
};
var enabledLayers = new HashSet<string>();
if (options.UseDebug)
{
enabledExtensions.Add(ExtDebugUtils.ExtensionName);
enabledExtensions.Add(ExtDebugReport.ExtensionName);
if (IsLayerAvailable(api, "VK_LAYER_KHRONOS_validation"))
enabledLayers.Add("VK_LAYER_KHRONOS_validation");
}
foreach (var layer in options.EnabledLayers)
enabledLayers.Add(layer);
var ppEnabledExtensions = stackalloc IntPtr[enabledExtensions.Count];
var ppEnabledLayers = stackalloc IntPtr[enabledLayers.Count];
for (var i = 0; i < enabledExtensions.Count; i++)
ppEnabledExtensions[i] = Marshal.StringToHGlobalAnsi(enabledExtensions[i]);
var layers = enabledLayers.ToList();
for (var i = 0; i < enabledLayers.Count; i++)
ppEnabledLayers[i] = Marshal.StringToHGlobalAnsi(layers[i]);
var instanceCreateInfo = new InstanceCreateInfo
{
SType = StructureType.InstanceCreateInfo,
PApplicationInfo = &applicationInfo,
PpEnabledExtensionNames = (byte**)ppEnabledExtensions,
PpEnabledLayerNames = (byte**)ppEnabledLayers,
EnabledExtensionCount = (uint)enabledExtensions.Count,
EnabledLayerCount = (uint)enabledLayers.Count
};
api.CreateInstance(in instanceCreateInfo, null, out var instance).ThrowOnError();
Marshal.FreeHGlobal(applicationName);
Marshal.FreeHGlobal(engineName);
for (var i = 0; i < enabledExtensions.Count; i++) Marshal.FreeHGlobal(ppEnabledExtensions[i]);
for (var i = 0; i < enabledLayers.Count; i++) Marshal.FreeHGlobal(ppEnabledLayers[i]);
return new VulkanInstance(instance, api);
}
private static unsafe bool IsLayerAvailable(Vk api, string layerName)
{
uint layerPropertiesCount;
api.EnumerateInstanceLayerProperties(&layerPropertiesCount, null).ThrowOnError();
var layerProperties = new LayerProperties[layerPropertiesCount];
fixed (LayerProperties* pLayerProperties = layerProperties)
{
api.EnumerateInstanceLayerProperties(&layerPropertiesCount, layerProperties).ThrowOnError();
for (var i = 0; i < layerPropertiesCount; i++)
{
var currentLayerName = Marshal.PtrToStringAnsi((IntPtr)pLayerProperties[i].LayerName);
if (currentLayerName == layerName) return true;
}
}
return false;
}
}
}
|