forked from amkovkov/GranuSightSoftware2
244 lines
9.7 KiB
C#
244 lines
9.7 KiB
C#
// Основан на примере GpuInterop Avalonia
|
|
// https://github.com/AvaloniaUI/Avalonia/blob/5f3dbae22244e830b464fc680c6c28ca124be41a/samples/GpuInterop/VulkanDemo/VulkanContext.cs
|
|
|
|
using Silk.NET.Core;
|
|
using Silk.NET.Vulkan;
|
|
using Silk.NET.Vulkan.Extensions.KHR;
|
|
|
|
using Semaphore = Silk.NET.Vulkan.Semaphore;
|
|
|
|
namespace GSS2.Vulkan;
|
|
|
|
unsafe public class VulkanContext : IDisposable
|
|
{
|
|
private bool _disposedValue;
|
|
|
|
public Vk Api { get; init; }
|
|
public Instance Instance { get; init; }
|
|
public PhysicalDevice PhysicalDevice { get; init; }
|
|
public Device Device { get; init; }
|
|
public uint QueueFamilyIndex { get; init; }
|
|
public Queue Queue { get; init; }
|
|
public Semaphore ImageExportedSemaphore { get; init; }
|
|
public Semaphore ImageRenderedSemaphore { get; init; }
|
|
public CommandPool CommandPool { get; init; }
|
|
public CommandBuffer CommandBuffer { get; init; }
|
|
public KhrExternalMemoryFd KhrExternalMemoryFd { get; init; }
|
|
public KhrExternalSemaphoreFd KhrExternalSemaphoreFd { get; init; }
|
|
public KhrExternalFenceFd KhrExternalFenceFd { get; init; }
|
|
|
|
public VulkanContext(string applicationName, string engineName)
|
|
{
|
|
Api = Vk.GetApi();
|
|
|
|
List<string> instanceExtensions =
|
|
[
|
|
"VK_KHR_get_physical_device_properties2",
|
|
"VK_KHR_external_memory_capabilities",
|
|
"VK_KHR_external_fence_capabilities",
|
|
"VK_KHR_external_semaphore_capabilities",
|
|
"VK_EXT_debug_utils"
|
|
];
|
|
List<string> instanceLayers =
|
|
[
|
|
|
|
];
|
|
List<string> deviceExtensions =
|
|
[
|
|
"VK_KHR_external_memory",
|
|
"VK_KHR_external_memory_fd",
|
|
"VK_KHR_external_semaphore",
|
|
"VK_KHR_external_semaphore_fd",
|
|
"VK_KHR_external_fence",
|
|
"VK_KHR_external_fence_fd"
|
|
];
|
|
|
|
Instance = CreateInstance(Api, applicationName, engineName, instanceExtensions, instanceLayers);
|
|
PhysicalDevice = FindPhysicalDevice(Api, Instance, deviceExtensions);
|
|
(Device, QueueFamilyIndex) = CreateDevice(Api, Instance, PhysicalDevice, deviceExtensions);
|
|
Queue = CreateQueue(Api, Device, QueueFamilyIndex);
|
|
ImageExportedSemaphore = CreateSemaphore(Api, Device);
|
|
ImageRenderedSemaphore = CreateSemaphore(Api, Device);
|
|
CommandPool = CreateCommandPool(Api, Device, QueueFamilyIndex);
|
|
CommandBuffer = CreateCommandBuffer(Api, Device, CommandPool);
|
|
|
|
if (!Api.TryGetDeviceExtension<KhrExternalMemoryFd>(Instance, Device, out var khrExternalMemoryFd))
|
|
throw new Exception("KhrExternalMemoryFd import error");
|
|
KhrExternalMemoryFd = khrExternalMemoryFd;
|
|
if (!Api.TryGetDeviceExtension<KhrExternalSemaphoreFd>(Instance, Device, out var khrExternalSemaphoreFd))
|
|
throw new Exception("KhrExternalMemoryFd import error");
|
|
KhrExternalSemaphoreFd = khrExternalSemaphoreFd;
|
|
if (!Api.TryGetDeviceExtension<KhrExternalFenceFd>(Instance, Device, out var khrExternalFenceFd))
|
|
throw new Exception("KhrExternalFenceFd import error");
|
|
KhrExternalFenceFd = khrExternalFenceFd;
|
|
}
|
|
|
|
private static Instance CreateInstance(Vk api, string applicationName, string engineName, List<string> extentions, List<string> layers)
|
|
{
|
|
using var pApplicationName = new ByteString(applicationName);
|
|
using var pEngineName = new ByteString(engineName);
|
|
var applicationInfo = new ApplicationInfo
|
|
{
|
|
SType = StructureType.ApplicationInfo,
|
|
PApplicationName = pApplicationName,
|
|
PEngineName = pEngineName,
|
|
ApiVersion = new Version32(1, 1, 0),
|
|
EngineVersion = new Version32(1, 0, 0),
|
|
ApplicationVersion = new Version32(1, 0, 0)
|
|
};
|
|
|
|
using var pExtensions = new ByteStringList(extentions);
|
|
using var pLayers = new ByteStringList(layers);
|
|
var instanceCreateInfo = new InstanceCreateInfo
|
|
{
|
|
SType = StructureType.InstanceCreateInfo,
|
|
PApplicationInfo = &applicationInfo,
|
|
PpEnabledExtensionNames = pExtensions,
|
|
EnabledExtensionCount = checked((uint)pExtensions.Count),
|
|
PpEnabledLayerNames = pLayers,
|
|
EnabledLayerCount = checked((uint)pLayers.Count),
|
|
Flags = default
|
|
};
|
|
|
|
api.CreateInstance(in instanceCreateInfo, null, out var Instance).ThrowOnError();
|
|
|
|
return Instance;
|
|
}
|
|
private static PhysicalDevice FindPhysicalDevice(Vk api, Instance instance, List<string> extensions)
|
|
{
|
|
uint count = 0;
|
|
api.EnumeratePhysicalDevices(instance, ref count, null).ThrowOnError();
|
|
var physicalDevices = stackalloc PhysicalDevice[(int)count];
|
|
api.EnumeratePhysicalDevices(instance, ref count, physicalDevices).ThrowOnError();
|
|
|
|
for (uint c = 0; c < count; c++)
|
|
{
|
|
if (extensions.Any(e => !api.IsDeviceExtensionPresent(physicalDevices[c], e)))
|
|
continue;
|
|
return physicalDevices[c];
|
|
}
|
|
|
|
throw new Exception("Suшtable Device not found");
|
|
}
|
|
private static (Device device, uint queueFamilyIndex) CreateDevice(Vk api, Instance instance, PhysicalDevice physicalDevice, List<string> extensions)
|
|
{
|
|
uint queueFamilyCount = 0;
|
|
api.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, ref queueFamilyCount, null);
|
|
var queueFamilyProperties = new QueueFamilyProperties[(int)queueFamilyCount];
|
|
fixed (QueueFamilyProperties* pQueueFamilyProperties = queueFamilyProperties)
|
|
api.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, ref queueFamilyCount, pQueueFamilyProperties);
|
|
|
|
for (uint i = 0; i < queueFamilyCount; i++)
|
|
{
|
|
var queueFamily = queueFamilyProperties[i];
|
|
if (!queueFamily.QueueFlags.HasFlag(QueueFlags.GraphicsBit))
|
|
continue;
|
|
|
|
var queuePriorities = new float[(int)queueFamily.QueueCount];
|
|
|
|
for (var j = 0; j < queueFamily.QueueCount; j++)
|
|
queuePriorities[j] = 1f;
|
|
|
|
var features = new PhysicalDeviceFeatures();
|
|
|
|
Device device;
|
|
fixed (float* pQueuePriorities = queuePriorities)
|
|
{
|
|
var queueCreateInfo = new DeviceQueueCreateInfo
|
|
{
|
|
SType = StructureType.DeviceQueueCreateInfo,
|
|
QueueFamilyIndex = i,
|
|
QueueCount = queueFamily.QueueCount,
|
|
PQueuePriorities = pQueuePriorities
|
|
};
|
|
|
|
using var pEnabledDeviceExtensions = new ByteStringList(extensions);
|
|
var deviceCreateInfo = new DeviceCreateInfo
|
|
{
|
|
SType = StructureType.DeviceCreateInfo,
|
|
QueueCreateInfoCount = 1,
|
|
PQueueCreateInfos = &queueCreateInfo,
|
|
PpEnabledExtensionNames = pEnabledDeviceExtensions,
|
|
EnabledExtensionCount = checked((uint)pEnabledDeviceExtensions.Count),
|
|
PEnabledFeatures = &features
|
|
};
|
|
|
|
api.CreateDevice(physicalDevice, in deviceCreateInfo, null, out device).ThrowOnError();
|
|
|
|
return (device, i);
|
|
}
|
|
}
|
|
throw new Exception("Cannot create device");
|
|
}
|
|
private static Queue CreateQueue(Vk api, Device device, uint queueFamilyIndex)
|
|
{
|
|
api.GetDeviceQueue(device, queueFamilyIndex, 0, out var queue);
|
|
return queue;
|
|
}
|
|
private static Semaphore CreateSemaphore(Vk api, Device device)
|
|
{
|
|
var semaphoreExportInfo = new ExportSemaphoreCreateInfo
|
|
{
|
|
SType = StructureType.ExportSemaphoreCreateInfo,
|
|
HandleTypes = ExternalSemaphoreHandleTypeFlags.OpaqueFDBit
|
|
};
|
|
var semaphoreCreateInfo = new SemaphoreCreateInfo
|
|
{
|
|
SType = StructureType.SemaphoreCreateInfo,
|
|
PNext = &semaphoreExportInfo
|
|
};
|
|
|
|
api.CreateSemaphore(device, in semaphoreCreateInfo, null, out var semaphore).ThrowOnError();
|
|
return semaphore;
|
|
}
|
|
private static CommandPool CreateCommandPool(Vk api, Device device, uint queueFamilyIndex)
|
|
{
|
|
var commandPoolCreateInfo = new CommandPoolCreateInfo
|
|
{
|
|
SType = StructureType.CommandPoolCreateInfo,
|
|
Flags = CommandPoolCreateFlags.ResetCommandBufferBit,
|
|
QueueFamilyIndex = queueFamilyIndex
|
|
};
|
|
api.CreateCommandPool(device, &commandPoolCreateInfo, null, out var commandPool).ThrowOnError();
|
|
|
|
return commandPool;
|
|
}
|
|
private static CommandBuffer CreateCommandBuffer(Vk api, Device device, CommandPool commandPool)
|
|
{
|
|
var commandBufferAllocateInfo = new CommandBufferAllocateInfo
|
|
{
|
|
SType = StructureType.CommandBufferAllocateInfo,
|
|
CommandPool = commandPool,
|
|
Level = CommandBufferLevel.Primary,
|
|
CommandBufferCount = 1
|
|
};
|
|
|
|
api.AllocateCommandBuffers(device, &commandBufferAllocateInfo, out var commandBuffer).ThrowOnError();
|
|
|
|
return commandBuffer;
|
|
}
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
if (!_disposedValue)
|
|
{
|
|
if (disposing)
|
|
{
|
|
if (Api is null)
|
|
return;
|
|
Api.DestroySemaphore(Device, ImageExportedSemaphore, null);
|
|
Api.DestroySemaphore(Device, ImageRenderedSemaphore, null);
|
|
Api.FreeCommandBuffers(Device, CommandPool, [CommandBuffer]);
|
|
Api.DestroyCommandPool(Device, CommandPool, null);
|
|
Api.DestroyDevice(Device, null);
|
|
}
|
|
_disposedValue = true;
|
|
}
|
|
}
|
|
public void Dispose()
|
|
{
|
|
Dispose(disposing: true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
}
|