forked from amkovkov/GranuSightSoftware2
fix: CameraView memory leakage
This commit is contained in:
@@ -21,7 +21,7 @@
|
|||||||
<PackageReference Include="OpenCvSharp4.runtime.linux-arm" Version="4.11.0.20250506" />
|
<PackageReference Include="OpenCvSharp4.runtime.linux-arm" Version="4.11.0.20250506" />
|
||||||
<PackageReference Include="System.Device.Gpio" Version="4.0.1" />
|
<PackageReference Include="System.Device.Gpio" Version="4.0.1" />
|
||||||
<PackageReference Include="Iot.Device.Bindings" Version="4.0.1" />
|
<PackageReference Include="Iot.Device.Bindings" Version="4.0.1" />
|
||||||
<PackageReference Include="LibCameraSharp" Version="0.5.2-20260116" />
|
<PackageReference Include="LibCameraSharp" Version="0.5.2-20260129-5" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -716,7 +716,6 @@ public class CameraService : IDisposable
|
|||||||
|
|
||||||
_camera.RequestCompleted += RequestCompleted;
|
_camera.RequestCompleted += RequestCompleted;
|
||||||
result = _camera.QueueRequest(request);
|
result = _camera.QueueRequest(request);
|
||||||
Console.WriteLine(result);
|
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
{
|
{
|
||||||
_camera.RequestCompleted -= RequestCompleted;
|
_camera.RequestCompleted -= RequestCompleted;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ public static class DependencyInjectionHelper
|
|||||||
.AddSingleton<MainView>()
|
.AddSingleton<MainView>()
|
||||||
.AddSingleton<MainViewModel>()
|
.AddSingleton<MainViewModel>()
|
||||||
.AddSingleton<ResourcesView>()
|
.AddSingleton<ResourcesView>()
|
||||||
.AddSingleton<ResourcesViewModel>();
|
.AddSingleton<ResourcesViewModel>()
|
||||||
// .AddSingleton<CameraView>()
|
.AddSingleton<CameraView>()
|
||||||
// .AddSingleton<CameraViewModel>();
|
.AddSingleton<CameraViewModel>();
|
||||||
}
|
}
|
||||||
@@ -13,7 +13,7 @@ public class CameraViewModel : ViewModelBase
|
|||||||
{
|
{
|
||||||
_cameraService = cameraService;
|
_cameraService = cameraService;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_logger.LogInformation("Initialized");
|
_logger.LogInformation("{} initialized", nameof(CameraViewModel));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<(FrameBuffer, StreamConfiguration)?> CaptureImage(int bufferId)
|
public async Task<(FrameBuffer, StreamConfiguration)?> CaptureImage(int bufferId)
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ public partial class MainViewModel : ViewModelBase
|
|||||||
[ObservableProperty] private CameraViewModel _cameraViewModel;
|
[ObservableProperty] private CameraViewModel _cameraViewModel;
|
||||||
[ObservableProperty] private ResourcesViewModel _resourcesViewModel;
|
[ObservableProperty] private ResourcesViewModel _resourcesViewModel;
|
||||||
|
|
||||||
public MainViewModel(ILogger<MainViewModel> logger, ResourcesViewModel resourcesViewModel)
|
public MainViewModel(ILogger<MainViewModel> logger, CameraViewModel cameraViewModel, ResourcesViewModel resourcesViewModel)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
// CameraViewModel = cameraViewModel;
|
CameraViewModel = cameraViewModel;
|
||||||
ResourcesViewModel = resourcesViewModel;
|
ResourcesViewModel = resourcesViewModel;
|
||||||
_logger.LogInformation("{} initialized", nameof(MainViewModel));
|
_logger.LogInformation("{} initialized", nameof(MainViewModel));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ public partial class ResourcesViewModel : ViewModelBase, IDisposable
|
|||||||
[ObservableProperty] private ObservableCollection<Axis> _memoryUsageSeriesXAxes;
|
[ObservableProperty] private ObservableCollection<Axis> _memoryUsageSeriesXAxes;
|
||||||
[ObservableProperty] private ObservableCollection<ISeries> _memoryUsagePieSeries;
|
[ObservableProperty] private ObservableCollection<ISeries> _memoryUsagePieSeries;
|
||||||
|
|
||||||
|
|
||||||
[ObservableProperty] private int _intervalMs = 500;
|
[ObservableProperty] private int _intervalMs = 500;
|
||||||
[ObservableProperty] private int _chartsHistorySize = 120;
|
[ObservableProperty] private int _chartsHistorySize = 120;
|
||||||
private readonly System.Timers.Timer _updateTimer;
|
private readonly System.Timers.Timer _updateTimer;
|
||||||
@@ -409,6 +408,7 @@ public partial class ResourcesViewModel : ViewModelBase, IDisposable
|
|||||||
memoryUsageValues.Add(Math.Round(snapshot.MemoryUsage.UsedMB, 2));
|
memoryUsageValues.Add(Math.Round(snapshot.MemoryUsage.UsedMB, 2));
|
||||||
while (memoryUsageValues.Count > ChartsHistorySize)
|
while (memoryUsageValues.Count > ChartsHistorySize)
|
||||||
memoryUsageValues.RemoveAt(0);
|
memoryUsageValues.RemoveAt(0);
|
||||||
|
// _logger.LogInformation("Memory leakage: {} MB/s", (memoryUsageValues.TakeLast(10).Average() - memoryUsageValues.TakeLast(20).Take(10).Average()) / 5.0);
|
||||||
}
|
}
|
||||||
if (MemoryUsageSeriesYAxes.Count() == 1)
|
if (MemoryUsageSeriesYAxes.Count() == 1)
|
||||||
MemoryUsageSeriesYAxes.First().MaxLimit = Math.Round(snapshot.MemoryUsage.TotalMB);
|
MemoryUsageSeriesYAxes.First().MaxLimit = Math.Round(snapshot.MemoryUsage.TotalMB);
|
||||||
|
|||||||
+274
-212
@@ -1,105 +1,128 @@
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.LogicalTree;
|
using Avalonia.LogicalTree;
|
||||||
using Avalonia.Platform;
|
using Avalonia.Platform;
|
||||||
using Avalonia.Rendering.Composition;
|
using Avalonia.Rendering.Composition;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
|
|
||||||
using GSS2.Test.ViewModels;
|
using GSS2.Test.ViewModels;
|
||||||
using GSS2.Vulkan;
|
using GSS2.Vulkan;
|
||||||
|
|
||||||
using LibCameraSharp;
|
using LibCameraSharp;
|
||||||
|
|
||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
using Silk.NET.Vulkan.Extensions.KHR;
|
using Silk.NET.Vulkan.Extensions.KHR;
|
||||||
|
|
||||||
using Image = Silk.NET.Vulkan.Image;
|
using Image = Silk.NET.Vulkan.Image;
|
||||||
|
|
||||||
namespace GSS2.Test.Views;
|
namespace GSS2.Test.Views;
|
||||||
|
|
||||||
interface IImage
|
public class VulkanImageResources
|
||||||
{
|
{
|
||||||
public (IPlatformHandle handle, PlatformGraphicsExternalImageProperties properties, Silk.NET.Vulkan.Semaphore semaphore) Export();
|
public Image ImportImage { get; init; }
|
||||||
|
public DeviceMemory ImportMemory { get; init; }
|
||||||
|
public Image ExportImage { get; init; }
|
||||||
|
public DeviceMemory ExportMemory { get; init; }
|
||||||
}
|
}
|
||||||
interface IRenderer
|
class VulkanExportedImage
|
||||||
{
|
{
|
||||||
public abstract IImage ImportOrUpdate(int fd, int width, int height);
|
public required int ImageExportedSemaphoreFd { get; init; }
|
||||||
}
|
public required int ImageRenderedSemaphoreFd { get; init; }
|
||||||
|
public required int OrignalFd { get; init; }
|
||||||
|
public required int ImageFd { get; init; }
|
||||||
|
public required int ImageWidth { get; init; }
|
||||||
|
public required int ImageHeight { get; init; }
|
||||||
|
public required ulong ImageMemorySize { get; init; }
|
||||||
|
public required int WaitSemaphoreFd { get; init; }
|
||||||
|
public required int SignalSemaphoreFd { get; init; }
|
||||||
|
public required VulkanImageResources Resources { get; init; }
|
||||||
|
|
||||||
class VkImage
|
public (IPlatformHandle imageHandle, PlatformGraphicsExternalImageProperties imageProperties, IPlatformHandle waitSemaphoreHandle, IPlatformHandle signalSemaphoreHandle) Export()
|
||||||
{
|
|
||||||
public int Fd { get; set; }
|
|
||||||
public int Width { get; set; }
|
|
||||||
public int Height { get; set; }
|
|
||||||
public ulong MemorySize { get; set; }
|
|
||||||
public Silk.NET.Vulkan.Semaphore Semaphore { get; set; }
|
|
||||||
|
|
||||||
public (IPlatformHandle handle, PlatformGraphicsExternalImageProperties properties, Silk.NET.Vulkan.Semaphore semaphore) Export()
|
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
new PlatformHandle(new IntPtr(Fd), KnownPlatformGraphicsExternalImageHandleTypes.VulkanOpaquePosixFileDescriptor),
|
new PlatformHandle(new IntPtr(ImageFd), KnownPlatformGraphicsExternalImageHandleTypes.VulkanOpaquePosixFileDescriptor),
|
||||||
new PlatformGraphicsExternalImageProperties
|
new PlatformGraphicsExternalImageProperties
|
||||||
{
|
{
|
||||||
Width = Width,
|
Width = ImageWidth,
|
||||||
Height = Height,
|
Height = ImageHeight,
|
||||||
Format = PlatformGraphicsExternalImageFormat.B8G8R8A8UNorm,
|
Format = PlatformGraphicsExternalImageFormat.B8G8R8A8UNorm,
|
||||||
MemorySize = MemorySize
|
MemorySize = ImageMemorySize
|
||||||
},
|
},
|
||||||
Semaphore
|
new PlatformHandle(new IntPtr(WaitSemaphoreFd), KnownPlatformGraphicsExternalSemaphoreHandleTypes.VulkanOpaquePosixFileDescriptor),
|
||||||
|
new PlatformHandle(new IntPtr(SignalSemaphoreFd), KnownPlatformGraphicsExternalSemaphoreHandleTypes.VulkanOpaquePosixFileDescriptor)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
class VkRenderer
|
class VulkanRenderer
|
||||||
{
|
{
|
||||||
[DllImport("libc")] private static extern int dup(int fd);
|
[DllImport("libc")] private static extern int dup(int fd);
|
||||||
readonly VulkanContext context = new VulkanContext("GSS2.Test", "CameraView");
|
[DllImport("libc")] private static extern int close(int fd);
|
||||||
|
private readonly VulkanContext _context = new VulkanContext("GSS2.Test", "CameraView");
|
||||||
|
|
||||||
public IPlatformHandle ExportSemaphore(bool renderFinished)
|
unsafe public VulkanExportedImage Import(int imageFd, int width, int height, int stride, int? fenceFd, bool initializationFrame)
|
||||||
{
|
{
|
||||||
int fd = context.ExportSemaphoreFd(renderFinished ? context.RenderFinishedSemaphore : context.ImageAvailableSemaphore);
|
// Console.WriteLine("Import 1");
|
||||||
return new PlatformHandle(new IntPtr(fd), KnownPlatformGraphicsExternalImageHandleTypes.VulkanOpaquePosixFileDescriptor);
|
var imageFdDuplicate = dup(imageFd);
|
||||||
}
|
// Console.WriteLine("Import 2");
|
||||||
|
|
||||||
unsafe public VkImage ImportOrUpdate(int fd, int width, int height, int stride)
|
|
||||||
{
|
|
||||||
var fdDup = dup(fd);
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
FenceCreateInfo fenceInfo = new FenceCreateInfo
|
// Console.WriteLine("Import 3");
|
||||||
{
|
var imageExportedSemaphore = _context.ImageExportedSemaphore;
|
||||||
SType = StructureType.FenceCreateInfo
|
var imageRenderedSemaphore = _context.ImageRenderedSemaphore;
|
||||||
};
|
var commandBuffer = _context.CommandBuffer;
|
||||||
context.Api.CreateFence(context.Device, &fenceInfo, null, out var fence).ThrowOnError();
|
|
||||||
|
|
||||||
var (importImage, importMemoryReqirements, importMemory) = ImportImage(fdDup, width, height, stride);
|
// Console.WriteLine("Import 7");
|
||||||
|
var imageExportedSemaphoreGetFdInfoKHR = new SemaphoreGetFdInfoKHR()
|
||||||
|
{
|
||||||
|
SType = StructureType.SemaphoreGetFDInfoKhr,
|
||||||
|
Semaphore = imageExportedSemaphore,
|
||||||
|
HandleType = ExternalSemaphoreHandleTypeFlags.OpaqueFDBit
|
||||||
|
};
|
||||||
|
_context.KhrExternalSemaphoreFd.GetSemaphoreF(_context.Device, in imageExportedSemaphoreGetFdInfoKHR, out var imageExportedSemaphoreFd).ThrowOnError();
|
||||||
|
|
||||||
|
// Console.WriteLine("Import 8");
|
||||||
|
var imageRenderedSemaphoreGetFdInfoKHR = new SemaphoreGetFdInfoKHR()
|
||||||
|
{
|
||||||
|
SType = StructureType.SemaphoreGetFDInfoKhr,
|
||||||
|
Semaphore = imageRenderedSemaphore,
|
||||||
|
HandleType = ExternalSemaphoreHandleTypeFlags.OpaqueFDBit
|
||||||
|
};
|
||||||
|
_context.KhrExternalSemaphoreFd.GetSemaphoreF(_context.Device, in imageRenderedSemaphoreGetFdInfoKHR, out var imageRenderedSemaphoreFd).ThrowOnError();
|
||||||
|
|
||||||
|
// Silk.NET.Vulkan.Fence imageCapturedFence = new Silk.NET.Vulkan.Fence(null);
|
||||||
|
// if (fenceFd is not null)
|
||||||
|
// {
|
||||||
|
// var importSemaphoreFdInfoKHR = new ImportFenceFdInfoKHR()
|
||||||
|
// {
|
||||||
|
// SType = StructureType.ImportSemaphoreFDInfoKhr,
|
||||||
|
// Fd = fenceFd.Value,
|
||||||
|
// Flags = FenceImportFlags.TemporaryBit,
|
||||||
|
// HandleType = ExternalFenceHandleTypeFlags.SyncFDBit
|
||||||
|
// };
|
||||||
|
// _context.KhrExternalFenceFd.ImportFenceF(_context.Device, &importSemaphoreFdInfoKHR);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Console.WriteLine("Import 9");
|
||||||
|
var (importImage, importMemoryReqirements, importMemory) = ImportImage(imageFdDuplicate, width, height, stride);
|
||||||
|
// Console.WriteLine("Import 10");
|
||||||
var (exportImage, exportMemoryReqirements, exportMemory) = CreateExportImage(width, height);
|
var (exportImage, exportMemoryReqirements, exportMemory) = CreateExportImage(width, height);
|
||||||
|
|
||||||
var commandPoolCreateInfo = new CommandPoolCreateInfo
|
// Console.WriteLine("Import 11");
|
||||||
{
|
|
||||||
SType = StructureType.CommandPoolCreateInfo,
|
|
||||||
Flags = CommandPoolCreateFlags.ResetCommandBufferBit,
|
|
||||||
QueueFamilyIndex = context.QueueFamilyIndex
|
|
||||||
};
|
|
||||||
context.Api.CreateCommandPool(context.Device, &commandPoolCreateInfo, null, out var commandPool).ThrowOnError();
|
|
||||||
|
|
||||||
var commandBufferAllocateInfo = new CommandBufferAllocateInfo
|
|
||||||
{
|
|
||||||
SType = StructureType.CommandBufferAllocateInfo,
|
|
||||||
CommandPool = commandPool,
|
|
||||||
Level = CommandBufferLevel.Primary,
|
|
||||||
CommandBufferCount = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
context.Api.AllocateCommandBuffers(context.Device, &commandBufferAllocateInfo, out var commandBuffers).ThrowOnError();
|
|
||||||
|
|
||||||
var commandBufferBeginInfo = new CommandBufferBeginInfo
|
var commandBufferBeginInfo = new CommandBufferBeginInfo
|
||||||
{
|
{
|
||||||
SType = StructureType.CommandBufferBeginInfo,
|
SType = StructureType.CommandBufferBeginInfo,
|
||||||
Flags = CommandBufferUsageFlags.OneTimeSubmitBit
|
Flags = CommandBufferUsageFlags.OneTimeSubmitBit
|
||||||
};
|
};
|
||||||
context.Api.BeginCommandBuffer(commandBuffers, &commandBufferBeginInfo).ThrowOnError();
|
_context.Api.BeginCommandBuffer(_context.CommandBuffer, &commandBufferBeginInfo).ThrowOnError();
|
||||||
|
|
||||||
TransitionImageLayout(commandBuffers, importImage, ImageLayout.Undefined, ImageLayout.TransferSrcOptimal);
|
// Console.WriteLine("Import 12");
|
||||||
TransitionImageLayout(commandBuffers, exportImage, ImageLayout.Undefined, ImageLayout.TransferDstOptimal);
|
TransitionImageLayout(_context.CommandBuffer, importImage, ImageLayout.Undefined, ImageLayout.TransferSrcOptimal);
|
||||||
|
TransitionImageLayout(_context.CommandBuffer, exportImage, ImageLayout.Undefined, ImageLayout.TransferDstOptimal);
|
||||||
|
|
||||||
var region = new ImageCopy
|
// Console.WriteLine("Import 13");
|
||||||
|
var imageCopy = new ImageCopy
|
||||||
{
|
{
|
||||||
SrcSubresource = new ImageSubresourceLayers
|
SrcSubresource = new ImageSubresourceLayers
|
||||||
{
|
{
|
||||||
@@ -119,55 +142,121 @@ class VkRenderer
|
|||||||
DstOffset = new Offset3D(0, 0, 0),
|
DstOffset = new Offset3D(0, 0, 0),
|
||||||
Extent = new Extent3D((uint)width, (uint)height, 1)
|
Extent = new Extent3D((uint)width, (uint)height, 1)
|
||||||
};
|
};
|
||||||
context.Api.CmdCopyImage(commandBuffers, importImage, ImageLayout.Undefined, exportImage, ImageLayout.Undefined, [region]);
|
_context.Api.CmdCopyImage(_context.CommandBuffer, importImage, ImageLayout.Undefined, exportImage, ImageLayout.Undefined, [imageCopy]);
|
||||||
|
|
||||||
TransitionImageLayout(commandBuffers, exportImage, ImageLayout.TransferDstOptimal, ImageLayout.General);
|
// Console.WriteLine("Import 14");
|
||||||
|
TransitionImageLayout(_context.CommandBuffer, exportImage, ImageLayout.TransferDstOptimal, ImageLayout.General);
|
||||||
|
|
||||||
context.Api.EndCommandBuffer(commandBuffers).ThrowOnError();
|
// Console.WriteLine("Import 154");
|
||||||
|
_context.Api.EndCommandBuffer(_context.CommandBuffer).ThrowOnError();
|
||||||
|
|
||||||
if (context.Api.TryGetDeviceExtension<KhrExternalMemoryFd>(context.Instance, context.Device, out var khrExternalMemoryFd))
|
// Console.WriteLine("Import 16");
|
||||||
Console.WriteLine("KhrExternalMemoryFd import success");
|
|
||||||
else
|
|
||||||
throw new Exception("KhrExternalMemoryFd import error");
|
|
||||||
var memoryGetFdInfoKHR = new MemoryGetFdInfoKHR
|
var memoryGetFdInfoKHR = new MemoryGetFdInfoKHR
|
||||||
{
|
{
|
||||||
SType = StructureType.MemoryGetFDInfoKhr,
|
SType = StructureType.MemoryGetFDInfoKhr,
|
||||||
Memory = exportMemory,
|
Memory = exportMemory,
|
||||||
HandleType = ExternalMemoryHandleTypeFlags.OpaqueFDBit
|
HandleType = ExternalMemoryHandleTypeFlags.OpaqueFDBit
|
||||||
};
|
};
|
||||||
khrExternalMemoryFd.GetMemoryF(context.Device, &memoryGetFdInfoKHR, out var vulkanFd).ThrowOnError();
|
_context.KhrExternalMemoryFd.GetMemoryF(_context.Device, &memoryGetFdInfoKHR, out var vulkanImageFd).ThrowOnError();
|
||||||
Console.WriteLine($"Image export success {vulkanFd}");
|
|
||||||
|
|
||||||
var renderFinished = context.RenderFinishedSemaphore;
|
// Console.WriteLine("Import 17");
|
||||||
|
// var waitSemaphoreIndex = 0;
|
||||||
|
// Silk.NET.Vulkan.Semaphore[] waitSemaphoresArray = new Silk.NET.Vulkan.Semaphore[
|
||||||
|
// !initializationFrame ? 1 : 0
|
||||||
|
// ];
|
||||||
|
// PipelineStageFlags[] pipelineStageFlagsArray = new PipelineStageFlags[waitSemaphoresArray.Length];
|
||||||
|
// if (!initializationFrame)
|
||||||
|
// {
|
||||||
|
// waitSemaphoresArray[waitSemaphoreIndex] = imageRenderedSemaphore;
|
||||||
|
// pipelineStageFlagsArray[waitSemaphoreIndex++] = PipelineStageFlags.AllGraphicsBit;
|
||||||
|
// }
|
||||||
|
// var waitSemaphoresSpan = new ReadOnlySpan<Silk.NET.Vulkan.Semaphore>(waitSemaphoresArray);
|
||||||
|
// var pipelineStageFlagsSpan = new ReadOnlySpan<PipelineStageFlags>(pipelineStageFlagsArray);
|
||||||
|
|
||||||
|
// fixed (PipelineStageFlags* pPipelineStageFlags = pipelineStageFlagsSpan)
|
||||||
|
// {
|
||||||
|
// fixed (Silk.NET.Vulkan.Semaphore* pWaitSemaphoresSpan = waitSemaphoresSpan)
|
||||||
|
// {
|
||||||
|
// var submitInfo = new SubmitInfo
|
||||||
|
// {
|
||||||
|
// SType = StructureType.SubmitInfo,
|
||||||
|
// CommandBufferCount = 1,
|
||||||
|
// PCommandBuffers = &commandBuffer,
|
||||||
|
// PSignalSemaphores = &imageExportedSemaphore,
|
||||||
|
// SignalSemaphoreCount = 1,
|
||||||
|
// PWaitSemaphores = pWaitSemaphoresSpan,
|
||||||
|
// PWaitDstStageMask = pPipelineStageFlags,
|
||||||
|
// WaitSemaphoreCount = checked((uint)waitSemaphoresArray.Length)
|
||||||
|
// };
|
||||||
|
// // Console.WriteLine("Import 18");
|
||||||
|
// _context.Api.QueueSubmit(_context.Queue, 1, &submitInfo, imageCapturedFence).ThrowOnError();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
ReadOnlySpan<PipelineStageFlags> pipelineStageFlags = [PipelineStageFlags.AllGraphicsBit];
|
||||||
|
fixed (PipelineStageFlags* pPipelineStageFlags = pipelineStageFlags)
|
||||||
|
{
|
||||||
|
ReadOnlySpan<Silk.NET.Vulkan.Semaphore> waitSemaphores =
|
||||||
|
[
|
||||||
|
imageRenderedSemaphore
|
||||||
|
];
|
||||||
var submitInfo = new SubmitInfo
|
var submitInfo = new SubmitInfo
|
||||||
{
|
{
|
||||||
SType = StructureType.SubmitInfo,
|
SType = StructureType.SubmitInfo,
|
||||||
CommandBufferCount = 1,
|
CommandBufferCount = 1,
|
||||||
PCommandBuffers = &commandBuffers,
|
PCommandBuffers = &commandBuffer,
|
||||||
PSignalSemaphores = &renderFinished,
|
PSignalSemaphores = &imageExportedSemaphore,
|
||||||
SignalSemaphoreCount = 1
|
SignalSemaphoreCount = 1,
|
||||||
|
PWaitSemaphores = initializationFrame ? null : &imageRenderedSemaphore,
|
||||||
|
WaitSemaphoreCount = initializationFrame ? 0u : 1u,
|
||||||
|
PWaitDstStageMask = initializationFrame ? null : pPipelineStageFlags
|
||||||
};
|
};
|
||||||
|
|
||||||
context.Api.QueueSubmit(context.Queue, 1, &submitInfo, fence).ThrowOnError();
|
// Console.WriteLine("Import 18");
|
||||||
context.Api.WaitForFences(context.Device, 1, &fence, true, ulong.MaxValue).ThrowOnError();
|
_context.Api.QueueSubmit(_context.Queue, 1, &submitInfo, new Silk.NET.Vulkan.Fence(UIntPtr.Zero)).ThrowOnError();
|
||||||
context.Api.ResetFences(context.Device, 1, &fence).ThrowOnError();
|
}
|
||||||
|
|
||||||
return new VkImage()
|
// Console.WriteLine("Import 19");
|
||||||
|
return new VulkanExportedImage
|
||||||
{
|
{
|
||||||
Width = width,
|
ImageExportedSemaphoreFd = imageExportedSemaphoreFd,
|
||||||
Height = height,
|
ImageRenderedSemaphoreFd = imageRenderedSemaphoreFd,
|
||||||
Fd = vulkanFd,
|
OrignalFd = imageFdDuplicate,
|
||||||
MemorySize = exportMemoryReqirements.Size
|
ImageWidth = width,
|
||||||
|
ImageHeight = height,
|
||||||
|
ImageFd = vulkanImageFd,
|
||||||
|
ImageMemorySize = exportMemoryReqirements.Size,
|
||||||
|
WaitSemaphoreFd = imageExportedSemaphoreFd,
|
||||||
|
SignalSemaphoreFd = imageRenderedSemaphoreFd,
|
||||||
|
Resources = new VulkanImageResources
|
||||||
|
{
|
||||||
|
ImportImage = importImage,
|
||||||
|
ImportMemory = importMemory,
|
||||||
|
ExportImage = exportImage,
|
||||||
|
ExportMemory = exportMemory
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Console.WriteLine(e.Message);
|
// Console.WriteLine(e.Message);
|
||||||
Console.WriteLine(e.StackTrace);
|
// Console.WriteLine(e.StackTrace);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe public void ClearResource(VulkanExportedImage image)
|
||||||
|
{
|
||||||
|
_context.Api.DestroyImage(_context.Device, image.Resources.ImportImage, null);
|
||||||
|
_context.Api.FreeMemory(_context.Device, image.Resources.ImportMemory, null);
|
||||||
|
_context.Api.DestroyImage(_context.Device, image.Resources.ExportImage, null);
|
||||||
|
_context.Api.FreeMemory(_context.Device, image.Resources.ExportMemory, null);
|
||||||
|
close(image.OrignalFd);
|
||||||
|
close(image.ImageFd);
|
||||||
|
close(image.ImageExportedSemaphoreFd);
|
||||||
|
close(image.ImageRenderedSemaphoreFd);
|
||||||
|
}
|
||||||
|
|
||||||
unsafe public (Image, MemoryRequirements, DeviceMemory) ImportImage(int fd, int width, int height, int stride)
|
unsafe public (Image, MemoryRequirements, DeviceMemory) ImportImage(int fd, int width, int height, int stride)
|
||||||
{
|
{
|
||||||
var subresourceLayout = new SubresourceLayout
|
var subresourceLayout = new SubresourceLayout
|
||||||
@@ -202,8 +291,8 @@ class VkRenderer
|
|||||||
SharingMode = SharingMode.Exclusive,
|
SharingMode = SharingMode.Exclusive,
|
||||||
InitialLayout = ImageLayout.Undefined
|
InitialLayout = ImageLayout.Undefined
|
||||||
};
|
};
|
||||||
context.Api.CreateImage(context.Device, &imageCreateInfo, null, out var image).ThrowOnError();
|
_context.Api.CreateImage(_context.Device, &imageCreateInfo, null, out var image).ThrowOnError();
|
||||||
context.Api.GetImageMemoryRequirements(context.Device, image, out var memoryReqirements);
|
_context.Api.GetImageMemoryRequirements(_context.Device, image, out var memoryReqirements);
|
||||||
|
|
||||||
var importMemoryFdInfoKHR = new ImportMemoryFdInfoKHR
|
var importMemoryFdInfoKHR = new ImportMemoryFdInfoKHR
|
||||||
{
|
{
|
||||||
@@ -218,8 +307,8 @@ class VkRenderer
|
|||||||
MemoryTypeIndex = checked((uint)FindMemoryType(memoryReqirements.MemoryTypeBits, MemoryPropertyFlags.DeviceLocalBit)),
|
MemoryTypeIndex = checked((uint)FindMemoryType(memoryReqirements.MemoryTypeBits, MemoryPropertyFlags.DeviceLocalBit)),
|
||||||
PNext = &importMemoryFdInfoKHR,
|
PNext = &importMemoryFdInfoKHR,
|
||||||
};
|
};
|
||||||
context.Api.AllocateMemory(context.Device, &memoryAllocateInfo, null, out var memory).ThrowOnError();
|
_context.Api.AllocateMemory(_context.Device, &memoryAllocateInfo, null, out var memory).ThrowOnError();
|
||||||
context.Api.BindImageMemory(context.Device, image, memory, 0).ThrowOnError();
|
_context.Api.BindImageMemory(_context.Device, image, memory, 0).ThrowOnError();
|
||||||
|
|
||||||
return (image, memoryReqirements, memory);
|
return (image, memoryReqirements, memory);
|
||||||
}
|
}
|
||||||
@@ -250,8 +339,8 @@ class VkRenderer
|
|||||||
SharingMode = SharingMode.Exclusive,
|
SharingMode = SharingMode.Exclusive,
|
||||||
InitialLayout = ImageLayout.Undefined,
|
InitialLayout = ImageLayout.Undefined,
|
||||||
};
|
};
|
||||||
context.Api.CreateImage(context.Device, &imageCreateInfo, null, out var image).ThrowOnError();
|
_context.Api.CreateImage(_context.Device, &imageCreateInfo, null, out var image).ThrowOnError();
|
||||||
context.Api.GetImageMemoryRequirements(context.Device, image, out var memoryReqirements);
|
_context.Api.GetImageMemoryRequirements(_context.Device, image, out var memoryReqirements);
|
||||||
|
|
||||||
var exportMemoryFdInfoKHR = new ExportMemoryAllocateInfoKHR
|
var exportMemoryFdInfoKHR = new ExportMemoryAllocateInfoKHR
|
||||||
{
|
{
|
||||||
@@ -265,15 +354,15 @@ class VkRenderer
|
|||||||
MemoryTypeIndex = checked((uint)FindMemoryType(memoryReqirements.MemoryTypeBits, MemoryPropertyFlags.DeviceLocalBit)),
|
MemoryTypeIndex = checked((uint)FindMemoryType(memoryReqirements.MemoryTypeBits, MemoryPropertyFlags.DeviceLocalBit)),
|
||||||
PNext = &exportMemoryFdInfoKHR,
|
PNext = &exportMemoryFdInfoKHR,
|
||||||
};
|
};
|
||||||
context.Api.AllocateMemory(context.Device, &exportAllocateInfo, null, out var memory).ThrowOnError();
|
_context.Api.AllocateMemory(_context.Device, &exportAllocateInfo, null, out var memory).ThrowOnError();
|
||||||
context.Api.BindImageMemory(context.Device, image, memory, 0).ThrowOnError();
|
_context.Api.BindImageMemory(_context.Device, image, memory, 0).ThrowOnError();
|
||||||
|
|
||||||
return (image, memoryReqirements, memory);
|
return (image, memoryReqirements, memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int FindMemoryType(uint typeFilter, MemoryPropertyFlags properties)
|
private int FindMemoryType(uint typeFilter, MemoryPropertyFlags properties)
|
||||||
{
|
{
|
||||||
context!.Api.GetPhysicalDeviceMemoryProperties(context.PhysicalDevice, out var memProps);
|
_context!.Api.GetPhysicalDeviceMemoryProperties(_context.PhysicalDevice, out var memProps);
|
||||||
for (int i = 0; i < memProps.MemoryTypeCount; i++)
|
for (int i = 0; i < memProps.MemoryTypeCount; i++)
|
||||||
if ((typeFilter & (1 << i)) != 0 && (memProps.MemoryTypes[i].PropertyFlags & properties) == properties)
|
if ((typeFilter & (1 << i)) != 0 && (memProps.MemoryTypes[i].PropertyFlags & properties) == properties)
|
||||||
return i;
|
return i;
|
||||||
@@ -299,7 +388,7 @@ class VkRenderer
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
context.Api.CmdPipelineBarrier(
|
_context.Api.CmdPipelineBarrier(
|
||||||
cmd,
|
cmd,
|
||||||
PipelineStageFlags.TopOfPipeBit,
|
PipelineStageFlags.TopOfPipeBit,
|
||||||
PipelineStageFlags.TransferBit,
|
PipelineStageFlags.TransferBit,
|
||||||
@@ -308,77 +397,56 @@ class VkRenderer
|
|||||||
0, null,
|
0, null,
|
||||||
1, &barrier);
|
1, &barrier);
|
||||||
}
|
}
|
||||||
// unsafe private void TransitionImageLayout(CommandBuffer cmd, Silk.NET.Vulkan.Image image, ImageLayout oldLayout, ImageLayout newLayout)
|
|
||||||
// {
|
|
||||||
// var barrier = new ImageMemoryBarrier
|
|
||||||
// {
|
|
||||||
// SType = StructureType.ImageMemoryBarrier,
|
|
||||||
// OldLayout = oldLayout,
|
|
||||||
// NewLayout = newLayout,
|
|
||||||
// SrcQueueFamilyIndex = 0,
|
|
||||||
// DstQueueFamilyIndex = 0,
|
|
||||||
// Image = image,
|
|
||||||
// SubresourceRange = new ImageSubresourceRange
|
|
||||||
// {
|
|
||||||
// AspectMask = ImageAspectFlags.ColorBit,
|
|
||||||
// BaseMipLevel = 0,
|
|
||||||
// LevelCount = 1,
|
|
||||||
// BaseArrayLayer = 0,
|
|
||||||
// LayerCount = 1
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// PipelineStageFlags srcStage;
|
|
||||||
// PipelineStageFlags dstStage;
|
|
||||||
|
|
||||||
// if (oldLayout == ImageLayout.Undefined && newLayout == ImageLayout.TransferDstOptimal)
|
|
||||||
// {
|
|
||||||
// barrier.SrcAccessMask = 0;
|
|
||||||
// barrier.DstAccessMask = AccessFlags.TransferWriteBit;
|
|
||||||
|
|
||||||
// srcStage = PipelineStageFlags.TopOfPipeBit;
|
|
||||||
// dstStage = PipelineStageFlags.TransferBit;
|
|
||||||
// }
|
|
||||||
// else if (oldLayout == ImageLayout.Undefined && newLayout == ImageLayout.ShaderReadOnlyOptimal)
|
|
||||||
// {
|
|
||||||
// barrier.SrcAccessMask = 0;
|
|
||||||
// barrier.DstAccessMask = AccessFlags.ShaderReadBit;
|
|
||||||
|
|
||||||
// srcStage = PipelineStageFlags.TopOfPipeBit;
|
|
||||||
// dstStage = PipelineStageFlags.FragmentShaderBit;
|
|
||||||
// }
|
|
||||||
// else if (oldLayout == ImageLayout.TransferDstOptimal && newLayout == ImageLayout.ShaderReadOnlyOptimal)
|
|
||||||
// {
|
|
||||||
// barrier.SrcAccessMask = AccessFlags.TransferWriteBit;
|
|
||||||
// barrier.DstAccessMask = AccessFlags.ShaderReadBit;
|
|
||||||
|
|
||||||
// srcStage = PipelineStageFlags.TransferBit;
|
|
||||||
// dstStage = PipelineStageFlags.FragmentShaderBit;
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// srcStage = PipelineStageFlags.AllCommandsBit;
|
|
||||||
// dstStage = PipelineStageFlags.AllCommandsBit;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// context!.Api.CmdPipelineBarrier(cmd, srcStage, dstStage, 0, 0, null, 0, null, 1, &barrier);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public partial class CameraView : Control
|
public partial class CameraView : Control
|
||||||
{
|
{
|
||||||
|
class PresentedFrame
|
||||||
|
{
|
||||||
|
public required ICompositionImportedGpuImage Image { get; init; }
|
||||||
|
public required ICompositionImportedGpuSemaphore Wait { get; init; }
|
||||||
|
public required ICompositionImportedGpuSemaphore Signal { get; init; }
|
||||||
|
public required VulkanExportedImage Vulkan { get; init; }
|
||||||
|
|
||||||
|
public async ValueTask DisposeAsync(VulkanRenderer? _renerer)
|
||||||
|
{
|
||||||
|
Dispatcher.UIThread.Invoke(() =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Image.DisposeAsync().AsTask();
|
||||||
|
Wait.DisposeAsync().AsTask();
|
||||||
|
Signal.DisposeAsync().AsTask();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{ex.Message}\n{ex.StackTrace}");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_renerer?.ClearResource(Vulkan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly ILogger<CameraView> _logger;
|
||||||
private bool _initialized = false;
|
private bool _initialized = false;
|
||||||
|
private bool _initializationFrame = true;
|
||||||
|
|
||||||
private Compositor? _compositor;
|
private Compositor? _compositor;
|
||||||
private CompositionSurfaceVisual? _visual;
|
private CompositionSurfaceVisual? _visual;
|
||||||
private ICompositionGpuInterop? _gpuInterop;
|
private ICompositionGpuInterop? _gpuInterop;
|
||||||
private CompositionDrawingSurface? Surface { get; set; }
|
private CompositionDrawingSurface? _surface;
|
||||||
|
|
||||||
|
private VulkanRenderer? _renerer;
|
||||||
|
private VulkanExportedImage? _latestImage;
|
||||||
|
private PresentedFrame? _lastFrame;
|
||||||
|
|
||||||
private bool _compositionRequested;
|
private bool _compositionRequested;
|
||||||
private VkRenderer? _renerer;
|
|
||||||
private VkImage? _latestImage;
|
|
||||||
private System.Timers.Timer? _updateTimer;
|
private System.Timers.Timer? _updateTimer;
|
||||||
|
|
||||||
public CameraView()
|
public CameraView(ILogger<CameraView> logger)
|
||||||
{ }
|
{
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
||||||
{
|
{
|
||||||
@@ -416,7 +484,7 @@ public partial class CameraView : Control
|
|||||||
{
|
{
|
||||||
_updateTimer?.Stop();
|
_updateTimer?.Stop();
|
||||||
_updateTimer?.Dispose();
|
_updateTimer?.Dispose();
|
||||||
Surface?.Dispose();
|
_surface?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
_initialized = false;
|
_initialized = false;
|
||||||
@@ -429,17 +497,18 @@ public partial class CameraView : Control
|
|||||||
var selfVisual = ElementComposition.GetElementVisual(this)!;
|
var selfVisual = ElementComposition.GetElementVisual(this)!;
|
||||||
_compositor = selfVisual.Compositor;
|
_compositor = selfVisual.Compositor;
|
||||||
|
|
||||||
Surface = _compositor.CreateDrawingSurface();
|
_surface = _compositor.CreateDrawingSurface();
|
||||||
_visual = _compositor.CreateSurfaceVisual();
|
_visual = _compositor.CreateSurfaceVisual();
|
||||||
_visual.Surface = Surface;
|
_visual.Surface = _surface;
|
||||||
ElementComposition.SetElementChildVisual(this, _visual);
|
ElementComposition.SetElementChildVisual(this, _visual);
|
||||||
_gpuInterop = await _compositor.TryGetCompositionGpuInterop();
|
_gpuInterop = await _compositor.TryGetCompositionGpuInterop();
|
||||||
_renerer = new VkRenderer();
|
_renerer = new VulkanRenderer();
|
||||||
_initialized = true;
|
_initialized = true;
|
||||||
|
_logger.LogInformation("{} initialized", nameof(CameraView));
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Error while initialization: \n{e.Message}\n{e.StackTrace}");
|
_logger.LogError(ex, "Error while {} initialization", nameof(CameraView));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -453,73 +522,52 @@ public partial class CameraView : Control
|
|||||||
base.OnPropertyChanged(change);
|
base.OnPropertyChanged(change);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RenderToSurface(VkImage image)
|
private void RenderToSurface(VulkanExportedImage image)
|
||||||
{
|
{
|
||||||
var (handle, properties, semaphore) = image.Export();
|
var (handle, properties, waitSemaphore, signalSemaphore) = image.Export();
|
||||||
|
|
||||||
var imageRenderedSemaphore = _gpuInterop!.ImportSemaphore(_renerer!.ExportSemaphore(false));
|
var imageExportedSemaphore = _gpuInterop!.ImportSemaphore(waitSemaphore);
|
||||||
imageRenderedSemaphore.ImportCompleted.ContinueWith(t =>
|
imageExportedSemaphore.ImportCompleted.ContinueWith(t =>
|
||||||
{
|
{
|
||||||
Console.WriteLine($"imageRenderedSemaphore.ImportCompleted {t.Status}");
|
if (t.IsCompletedSuccessfully)
|
||||||
if (t.Exception is not null)
|
return;
|
||||||
{
|
_logger.LogError(t.Exception, "Error while imageExported semaphore import");
|
||||||
Console.WriteLine($"Error: \n{t.Exception.Message}\n{t.Exception.StackTrace} ");
|
|
||||||
foreach (var e in t.Exception.InnerExceptions)
|
|
||||||
{
|
|
||||||
Console.WriteLine(e.Message);
|
|
||||||
Console.WriteLine(e.StackTrace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
var renderCompletedSemaphore = _gpuInterop!.ImportSemaphore(_renerer!.ExportSemaphore(true));
|
var imageRenderedSemaphore = _gpuInterop!.ImportSemaphore(signalSemaphore);
|
||||||
renderCompletedSemaphore.ImportCompleted.ContinueWith(t =>
|
imageExportedSemaphore.ImportCompleted.ContinueWith(t =>
|
||||||
{
|
{
|
||||||
Console.WriteLine($"renderCompletedSemaphore.ImportCompleted {t.Status}");
|
if (t.IsCompletedSuccessfully)
|
||||||
if (t.Exception is not null)
|
return;
|
||||||
{
|
_logger.LogError(t.Exception, "Error while imageRendered semaphore import");
|
||||||
Console.WriteLine($"Error: \n{t.Exception.Message}\n{t.Exception.StackTrace} ");
|
|
||||||
foreach (var e in t.Exception.InnerExceptions)
|
|
||||||
{
|
|
||||||
Console.WriteLine(e.Message);
|
|
||||||
Console.WriteLine(e.StackTrace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Console.WriteLine("ImportImage");
|
|
||||||
var importedImage = _gpuInterop!.ImportImage(handle, properties);
|
var importedImage = _gpuInterop!.ImportImage(handle, properties);
|
||||||
importedImage.ImportCompleted.ContinueWith(t =>
|
imageExportedSemaphore.ImportCompleted.ContinueWith(t =>
|
||||||
{
|
{
|
||||||
Console.WriteLine($"importedImage.ImportCompleted {t.Status}");
|
if (t.IsCompletedSuccessfully)
|
||||||
if (t.Exception is not null)
|
return;
|
||||||
{
|
_logger.LogError(t.Exception, "Error while image import");
|
||||||
Console.WriteLine($"Error: \n{t.Exception.Message}\n{t.Exception.StackTrace} ");
|
|
||||||
foreach (var e in t.Exception.InnerExceptions)
|
|
||||||
{
|
|
||||||
Console.WriteLine(e.Message);
|
|
||||||
Console.WriteLine(e.StackTrace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var frame = new PresentedFrame
|
||||||
|
{
|
||||||
|
Image = importedImage,
|
||||||
|
Wait = imageExportedSemaphore,
|
||||||
|
Signal = imageRenderedSemaphore,
|
||||||
|
Vulkan = image
|
||||||
|
};
|
||||||
|
|
||||||
Dispatcher.UIThread.Invoke(async () =>
|
Dispatcher.UIThread.Invoke(async () =>
|
||||||
{
|
{
|
||||||
await Surface!.UpdateWithSemaphoresAsync(importedImage, renderCompletedSemaphore, imageRenderedSemaphore)
|
await _surface!.UpdateWithSemaphoresAsync(importedImage, imageExportedSemaphore, imageRenderedSemaphore).ContinueWith(t =>
|
||||||
.ContinueWith((t) =>
|
|
||||||
{
|
{
|
||||||
Console.WriteLine($"UpdateWithSemaphoresAsync {t.Status}");
|
_updateTimer?.Start();
|
||||||
if (t.Exception is not null)
|
_lastFrame?.DisposeAsync(_renerer);
|
||||||
{
|
_lastFrame = frame;
|
||||||
Console.WriteLine($"Error while surface update: \n{t.Exception.Message}\n{t.Exception.StackTrace} ");
|
if (t.IsCompletedSuccessfully)
|
||||||
foreach (var e in t.Exception.InnerExceptions)
|
return;
|
||||||
{
|
_logger.LogError(t.Exception, "Error while image update");
|
||||||
Console.WriteLine(e.Message);
|
});
|
||||||
Console.WriteLine(e.StackTrace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
private void OnComposition()
|
private void OnComposition()
|
||||||
{
|
{
|
||||||
@@ -533,18 +581,32 @@ public partial class CameraView : Control
|
|||||||
}
|
}
|
||||||
private void Update(FrameBuffer? frameBuffer = null, StreamConfiguration? streamConfiguration = null)
|
private void Update(FrameBuffer? frameBuffer = null, StreamConfiguration? streamConfiguration = null)
|
||||||
{
|
{
|
||||||
|
// Console.WriteLine("Update 1");
|
||||||
if (!_initialized || _compositor is null)
|
if (!_initialized || _compositor is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (frameBuffer is not null && streamConfiguration is not null && _renerer is not null)
|
if (frameBuffer is not null &&
|
||||||
|
frameBuffer.Planes.Count() == 1 &&
|
||||||
|
streamConfiguration is not null &&
|
||||||
|
_renerer is not null)
|
||||||
{
|
{
|
||||||
var image = _renerer.ImportOrUpdate(frameBuffer.Planes.First().Fd.Get(), checked((int)streamConfiguration.Size.Width), checked((int)streamConfiguration.Size.Height), checked((int)streamConfiguration.Stride));
|
// Console.WriteLine("Update 2");
|
||||||
|
// var fenceFd = frameBuffer.ReleaseFence()?.Fd?.Release();
|
||||||
|
var image = _renerer.Import(
|
||||||
|
frameBuffer.Planes.First().Fd.Get(),
|
||||||
|
checked((int)streamConfiguration.Size.Width),
|
||||||
|
checked((int)streamConfiguration.Size.Height),
|
||||||
|
checked((int)streamConfiguration.Stride),
|
||||||
|
null, // fenceFd,
|
||||||
|
_initializationFrame);
|
||||||
|
// _renerer.ClearResource(image);
|
||||||
|
// Console.WriteLine("Update 3");
|
||||||
|
_initializationFrame = false;
|
||||||
_latestImage = image;
|
_latestImage = image;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_compositionRequested)
|
if (_compositionRequested)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_compositionRequested = true;
|
_compositionRequested = true;
|
||||||
_compositor?.RequestCompositionUpdate(OnComposition);
|
_compositor?.RequestCompositionUpdate(OnComposition);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
xmlns:local="using:GSS2.Test.Views"
|
xmlns:local="using:GSS2.Test.Views"
|
||||||
x:DataType="vm:MainViewModel"
|
x:DataType="vm:MainViewModel"
|
||||||
x:Class="GSS2.Test.Views.MainView">
|
x:Class="GSS2.Test.Views.MainView">
|
||||||
<!-- <ContentControl Content="{Binding CameraViewModel}"/> -->
|
<StackPanel Orientation="Vertical">
|
||||||
|
<ContentControl Content="{Binding CameraViewModel}" Width="200" Height="200"/>
|
||||||
<ContentControl Content="{Binding ResourcesViewModel}"/>
|
<ContentControl Content="{Binding ResourcesViewModel}"/>
|
||||||
|
</StackPanel>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
Series="{Binding CpuUsageSeries}"
|
Series="{Binding CpuUsageSeries}"
|
||||||
YAxes="{Binding CpuUsageSeriesYAxes}"
|
YAxes="{Binding CpuUsageSeriesYAxes}"
|
||||||
XAxes="{Binding CpuUsageSeriesXAxes}"
|
XAxes="{Binding CpuUsageSeriesXAxes}"
|
||||||
Height="300"
|
Height="150"
|
||||||
ZoomMode="None"
|
ZoomMode="None"
|
||||||
EasingFunction="{x:Null}" />
|
EasingFunction="{x:Null}" />
|
||||||
<lvc:CartesianChart
|
<lvc:CartesianChart
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
Series="{Binding CpuTemperatureSeries}"
|
Series="{Binding CpuTemperatureSeries}"
|
||||||
YAxes="{Binding CpuTemperatureSeriesYAxes}"
|
YAxes="{Binding CpuTemperatureSeriesYAxes}"
|
||||||
XAxes="{Binding CpuTemperatureSeriesXAxes}"
|
XAxes="{Binding CpuTemperatureSeriesXAxes}"
|
||||||
Height="300"
|
Height="150"
|
||||||
ZoomMode="None"
|
ZoomMode="None"
|
||||||
EasingFunction="{x:Null}" />
|
EasingFunction="{x:Null}" />
|
||||||
<lvc:CartesianChart
|
<lvc:CartesianChart
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
Series="{Binding MemoryUsageSeries}"
|
Series="{Binding MemoryUsageSeries}"
|
||||||
YAxes="{Binding MemoryUsageSeriesYAxes}"
|
YAxes="{Binding MemoryUsageSeriesYAxes}"
|
||||||
XAxes="{Binding MemoryUsageSeriesXAxes}"
|
XAxes="{Binding MemoryUsageSeriesXAxes}"
|
||||||
Height="300"
|
Height="150"
|
||||||
ZoomMode="None"
|
ZoomMode="None"
|
||||||
EasingFunction="{x:Null}" />
|
EasingFunction="{x:Null}" />
|
||||||
|
|
||||||
@@ -44,39 +44,39 @@
|
|||||||
<lvc:PieChart
|
<lvc:PieChart
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Height="120"
|
Height="60"
|
||||||
Width="120"
|
Width="60"
|
||||||
Series="{Binding Cpu0UsagePieSeries}" />
|
Series="{Binding Cpu0UsagePieSeries}" />
|
||||||
<lvc:PieChart
|
<lvc:PieChart
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Height="120"
|
Height="60"
|
||||||
Width="120"
|
Width="60"
|
||||||
Series="{Binding Cpu1UsagePieSeries}" />
|
Series="{Binding Cpu1UsagePieSeries}" />
|
||||||
<lvc:PieChart
|
<lvc:PieChart
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Height="120"
|
Height="60"
|
||||||
Width="120"
|
Width="60"
|
||||||
Series="{Binding Cpu2UsagePieSeries}" />
|
Series="{Binding Cpu2UsagePieSeries}" />
|
||||||
<lvc:PieChart
|
<lvc:PieChart
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Height="120"
|
Height="60"
|
||||||
Width="120"
|
Width="60"
|
||||||
Series="{Binding Cpu3UsagePieSeries}" />
|
Series="{Binding Cpu3UsagePieSeries}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
<lvc:PieChart
|
<lvc:PieChart
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Height="300"
|
Height="150"
|
||||||
Width="300"
|
Width="150"
|
||||||
Series="{Binding CpuTemperaturePieSeries}" />
|
Series="{Binding CpuTemperaturePieSeries}" />
|
||||||
<lvc:PieChart
|
<lvc:PieChart
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Height="300"
|
Height="150"
|
||||||
Width="300"
|
Width="150"
|
||||||
Series="{Binding MemoryUsagePieSeries}" />
|
Series="{Binding MemoryUsagePieSeries}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|||||||
@@ -19,8 +19,13 @@ unsafe public class VulkanContext : IDisposable
|
|||||||
public Device Device { get; init; }
|
public Device Device { get; init; }
|
||||||
public uint QueueFamilyIndex { get; init; }
|
public uint QueueFamilyIndex { get; init; }
|
||||||
public Queue Queue { get; init; }
|
public Queue Queue { get; init; }
|
||||||
public Semaphore ImageAvailableSemaphore { get; init; }
|
public Semaphore ImageExportedSemaphore { get; init; }
|
||||||
public Semaphore RenderFinishedSemaphore { 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)
|
public VulkanContext(string applicationName, string engineName)
|
||||||
{
|
{
|
||||||
@@ -30,6 +35,7 @@ unsafe public class VulkanContext : IDisposable
|
|||||||
[
|
[
|
||||||
"VK_KHR_get_physical_device_properties2",
|
"VK_KHR_get_physical_device_properties2",
|
||||||
"VK_KHR_external_memory_capabilities",
|
"VK_KHR_external_memory_capabilities",
|
||||||
|
"VK_KHR_external_fence_capabilities",
|
||||||
"VK_KHR_external_semaphore_capabilities",
|
"VK_KHR_external_semaphore_capabilities",
|
||||||
"VK_EXT_debug_utils"
|
"VK_EXT_debug_utils"
|
||||||
];
|
];
|
||||||
@@ -42,30 +48,29 @@ unsafe public class VulkanContext : IDisposable
|
|||||||
"VK_KHR_external_memory",
|
"VK_KHR_external_memory",
|
||||||
"VK_KHR_external_memory_fd",
|
"VK_KHR_external_memory_fd",
|
||||||
"VK_KHR_external_semaphore",
|
"VK_KHR_external_semaphore",
|
||||||
"VK_KHR_external_semaphore_fd"
|
"VK_KHR_external_semaphore_fd",
|
||||||
|
"VK_KHR_external_fence",
|
||||||
|
"VK_KHR_external_fence_fd"
|
||||||
];
|
];
|
||||||
|
|
||||||
Instance = CreateInstance(Api, applicationName, engineName, instanceExtensions, instanceLayers);
|
Instance = CreateInstance(Api, applicationName, engineName, instanceExtensions, instanceLayers);
|
||||||
PhysicalDevice = FindPhysicalDevice(Api, Instance, deviceExtensions);
|
PhysicalDevice = FindPhysicalDevice(Api, Instance, deviceExtensions);
|
||||||
(Device, QueueFamilyIndex) = CreateDevice(Api, Instance, PhysicalDevice, deviceExtensions);
|
(Device, QueueFamilyIndex) = CreateDevice(Api, Instance, PhysicalDevice, deviceExtensions);
|
||||||
Queue = CreateQueue(Api, Device, QueueFamilyIndex);
|
Queue = CreateQueue(Api, Device, QueueFamilyIndex);
|
||||||
ImageAvailableSemaphore = CreateSemaphore(Api, Device);
|
ImageExportedSemaphore = CreateSemaphore(Api, Device);
|
||||||
RenderFinishedSemaphore = CreateSemaphore(Api, Device);
|
ImageRenderedSemaphore = CreateSemaphore(Api, Device);
|
||||||
}
|
CommandPool = CreateCommandPool(Api, Device, QueueFamilyIndex);
|
||||||
|
CommandBuffer = CreateCommandBuffer(Api, Device, CommandPool);
|
||||||
|
|
||||||
public int ExportSemaphoreFd(Semaphore semaphore)
|
if (!Api.TryGetDeviceExtension<KhrExternalMemoryFd>(Instance, Device, out var khrExternalMemoryFd))
|
||||||
{
|
throw new Exception("KhrExternalMemoryFd import error");
|
||||||
if (!Api.TryGetDeviceExtension<KhrExternalSemaphoreFd>(Instance, Device, out var extension))
|
KhrExternalMemoryFd = khrExternalMemoryFd;
|
||||||
throw new InvalidOperationException($"No {KhrExternalSemaphoreFd.ExtensionName} device extension");
|
if (!Api.TryGetDeviceExtension<KhrExternalSemaphoreFd>(Instance, Device, out var khrExternalSemaphoreFd))
|
||||||
|
throw new Exception("KhrExternalMemoryFd import error");
|
||||||
var info = new SemaphoreGetFdInfoKHR()
|
KhrExternalSemaphoreFd = khrExternalSemaphoreFd;
|
||||||
{
|
if (!Api.TryGetDeviceExtension<KhrExternalFenceFd>(Instance, Device, out var khrExternalFenceFd))
|
||||||
SType = StructureType.SemaphoreGetFDInfoKhr,
|
throw new Exception("KhrExternalFenceFd import error");
|
||||||
Semaphore = semaphore,
|
KhrExternalFenceFd = khrExternalFenceFd;
|
||||||
HandleType = ExternalSemaphoreHandleTypeFlags.OpaqueFDBit
|
|
||||||
};
|
|
||||||
extension.GetSemaphoreF(Device, in info, out var fd).ThrowOnError();
|
|
||||||
return fd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Instance CreateInstance(Vk api, string applicationName, string engineName, List<string> extentions, List<string> layers)
|
private static Instance CreateInstance(Vk api, string applicationName, string engineName, List<string> extentions, List<string> layers)
|
||||||
@@ -186,6 +191,32 @@ unsafe public class VulkanContext : IDisposable
|
|||||||
api.CreateSemaphore(device, in semaphoreCreateInfo, null, out var semaphore).ThrowOnError();
|
api.CreateSemaphore(device, in semaphoreCreateInfo, null, out var semaphore).ThrowOnError();
|
||||||
return semaphore;
|
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)
|
protected virtual void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
@@ -195,8 +226,11 @@ unsafe public class VulkanContext : IDisposable
|
|||||||
{
|
{
|
||||||
if (Api is null)
|
if (Api is null)
|
||||||
return;
|
return;
|
||||||
Api.DestroySemaphore(Device, ImageAvailableSemaphore, null);
|
Api.DestroySemaphore(Device, ImageExportedSemaphore, null);
|
||||||
Api.DestroySemaphore(Device, RenderFinishedSemaphore, null);
|
Api.DestroySemaphore(Device, ImageRenderedSemaphore, null);
|
||||||
|
Api.FreeCommandBuffers(Device, CommandPool, [CommandBuffer]);
|
||||||
|
Api.DestroyCommandPool(Device, CommandPool, null);
|
||||||
|
Api.DestroyDevice(Device, null);
|
||||||
}
|
}
|
||||||
_disposedValue = true;
|
_disposedValue = true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user