diff --git a/GSS2.Core/GSS2.Core.csproj b/GSS2.Core/GSS2.Core.csproj
index f11cb3f..061e878 100644
--- a/GSS2.Core/GSS2.Core.csproj
+++ b/GSS2.Core/GSS2.Core.csproj
@@ -21,7 +21,7 @@
-
+
diff --git a/GSS2.Core/Hardware/CameraService.cs b/GSS2.Core/Hardware/CameraService.cs
index 78f27bf..ec53e1f 100644
--- a/GSS2.Core/Hardware/CameraService.cs
+++ b/GSS2.Core/Hardware/CameraService.cs
@@ -716,7 +716,6 @@ public class CameraService : IDisposable
_camera.RequestCompleted += RequestCompleted;
result = _camera.QueueRequest(request);
- Console.WriteLine(result);
if (result < 0)
{
_camera.RequestCompleted -= RequestCompleted;
diff --git a/GSS2.Test/DependencyInjectionHelper.cs b/GSS2.Test/DependencyInjectionHelper.cs
index d7755e6..91827dd 100644
--- a/GSS2.Test/DependencyInjectionHelper.cs
+++ b/GSS2.Test/DependencyInjectionHelper.cs
@@ -11,7 +11,7 @@ public static class DependencyInjectionHelper
.AddSingleton()
.AddSingleton()
.AddSingleton()
- .AddSingleton();
- // .AddSingleton()
- // .AddSingleton();
+ .AddSingleton()
+ .AddSingleton()
+ .AddSingleton();
}
\ No newline at end of file
diff --git a/GSS2.Test/ViewModels/CameraViewModel.cs b/GSS2.Test/ViewModels/CameraViewModel.cs
index 1ec2dba..1e11eb6 100644
--- a/GSS2.Test/ViewModels/CameraViewModel.cs
+++ b/GSS2.Test/ViewModels/CameraViewModel.cs
@@ -13,7 +13,7 @@ public class CameraViewModel : ViewModelBase
{
_cameraService = cameraService;
_logger = logger;
- _logger.LogInformation("Initialized");
+ _logger.LogInformation("{} initialized", nameof(CameraViewModel));
}
public async Task<(FrameBuffer, StreamConfiguration)?> CaptureImage(int bufferId)
diff --git a/GSS2.Test/ViewModels/MainViewModel.cs b/GSS2.Test/ViewModels/MainViewModel.cs
index 6c598d2..9e3caad 100644
--- a/GSS2.Test/ViewModels/MainViewModel.cs
+++ b/GSS2.Test/ViewModels/MainViewModel.cs
@@ -8,10 +8,10 @@ public partial class MainViewModel : ViewModelBase
[ObservableProperty] private CameraViewModel _cameraViewModel;
[ObservableProperty] private ResourcesViewModel _resourcesViewModel;
- public MainViewModel(ILogger logger, ResourcesViewModel resourcesViewModel)
+ public MainViewModel(ILogger logger, CameraViewModel cameraViewModel, ResourcesViewModel resourcesViewModel)
{
_logger = logger;
- // CameraViewModel = cameraViewModel;
+ CameraViewModel = cameraViewModel;
ResourcesViewModel = resourcesViewModel;
_logger.LogInformation("{} initialized", nameof(MainViewModel));
}
diff --git a/GSS2.Test/ViewModels/ResourcesViewModel.cs b/GSS2.Test/ViewModels/ResourcesViewModel.cs
index 9b36a37..dda898c 100644
--- a/GSS2.Test/ViewModels/ResourcesViewModel.cs
+++ b/GSS2.Test/ViewModels/ResourcesViewModel.cs
@@ -43,7 +43,6 @@ public partial class ResourcesViewModel : ViewModelBase, IDisposable
[ObservableProperty] private ObservableCollection _memoryUsageSeriesXAxes;
[ObservableProperty] private ObservableCollection _memoryUsagePieSeries;
-
[ObservableProperty] private int _intervalMs = 500;
[ObservableProperty] private int _chartsHistorySize = 120;
private readonly System.Timers.Timer _updateTimer;
@@ -409,6 +408,7 @@ public partial class ResourcesViewModel : ViewModelBase, IDisposable
memoryUsageValues.Add(Math.Round(snapshot.MemoryUsage.UsedMB, 2));
while (memoryUsageValues.Count > ChartsHistorySize)
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)
MemoryUsageSeriesYAxes.First().MaxLimit = Math.Round(snapshot.MemoryUsage.TotalMB);
diff --git a/GSS2.Test/Views/CameraView.axaml.cs b/GSS2.Test/Views/CameraView.axaml.cs
index f5bef49..fdbd2c8 100644
--- a/GSS2.Test/Views/CameraView.axaml.cs
+++ b/GSS2.Test/Views/CameraView.axaml.cs
@@ -1,105 +1,128 @@
using System.Runtime.InteropServices;
+
using Avalonia;
using Avalonia.Controls;
using Avalonia.LogicalTree;
using Avalonia.Platform;
using Avalonia.Rendering.Composition;
using Avalonia.Threading;
+
using GSS2.Test.ViewModels;
using GSS2.Vulkan;
+
using LibCameraSharp;
+
using Silk.NET.Vulkan;
using Silk.NET.Vulkan.Extensions.KHR;
+
using Image = Silk.NET.Vulkan.Image;
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 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()
+ public (IPlatformHandle imageHandle, PlatformGraphicsExternalImageProperties imageProperties, IPlatformHandle waitSemaphoreHandle, IPlatformHandle signalSemaphoreHandle) Export()
{
return (
- new PlatformHandle(new IntPtr(Fd), KnownPlatformGraphicsExternalImageHandleTypes.VulkanOpaquePosixFileDescriptor),
+ new PlatformHandle(new IntPtr(ImageFd), KnownPlatformGraphicsExternalImageHandleTypes.VulkanOpaquePosixFileDescriptor),
new PlatformGraphicsExternalImageProperties
{
- Width = Width,
- Height = Height,
+ Width = ImageWidth,
+ Height = ImageHeight,
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);
- 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);
- return new PlatformHandle(new IntPtr(fd), KnownPlatformGraphicsExternalImageHandleTypes.VulkanOpaquePosixFileDescriptor);
- }
-
- unsafe public VkImage ImportOrUpdate(int fd, int width, int height, int stride)
- {
- var fdDup = dup(fd);
+ // Console.WriteLine("Import 1");
+ var imageFdDuplicate = dup(imageFd);
+ // Console.WriteLine("Import 2");
try
{
- FenceCreateInfo fenceInfo = new FenceCreateInfo
- {
- SType = StructureType.FenceCreateInfo
- };
- context.Api.CreateFence(context.Device, &fenceInfo, null, out var fence).ThrowOnError();
+ // Console.WriteLine("Import 3");
+ var imageExportedSemaphore = _context.ImageExportedSemaphore;
+ var imageRenderedSemaphore = _context.ImageRenderedSemaphore;
+ var commandBuffer = _context.CommandBuffer;
- 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 commandPoolCreateInfo = new CommandPoolCreateInfo
- {
- 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();
-
+ // Console.WriteLine("Import 11");
var commandBufferBeginInfo = new CommandBufferBeginInfo
{
SType = StructureType.CommandBufferBeginInfo,
Flags = CommandBufferUsageFlags.OneTimeSubmitBit
};
- context.Api.BeginCommandBuffer(commandBuffers, &commandBufferBeginInfo).ThrowOnError();
+ _context.Api.BeginCommandBuffer(_context.CommandBuffer, &commandBufferBeginInfo).ThrowOnError();
- TransitionImageLayout(commandBuffers, importImage, ImageLayout.Undefined, ImageLayout.TransferSrcOptimal);
- TransitionImageLayout(commandBuffers, exportImage, ImageLayout.Undefined, ImageLayout.TransferDstOptimal);
+ // Console.WriteLine("Import 12");
+ 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
{
@@ -119,55 +142,121 @@ class VkRenderer
DstOffset = new Offset3D(0, 0, 0),
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(context.Instance, context.Device, out var khrExternalMemoryFd))
- Console.WriteLine("KhrExternalMemoryFd import success");
- else
- throw new Exception("KhrExternalMemoryFd import error");
+ // Console.WriteLine("Import 16");
var memoryGetFdInfoKHR = new MemoryGetFdInfoKHR
{
SType = StructureType.MemoryGetFDInfoKhr,
Memory = exportMemory,
HandleType = ExternalMemoryHandleTypeFlags.OpaqueFDBit
};
- khrExternalMemoryFd.GetMemoryF(context.Device, &memoryGetFdInfoKHR, out var vulkanFd).ThrowOnError();
- Console.WriteLine($"Image export success {vulkanFd}");
+ _context.KhrExternalMemoryFd.GetMemoryF(_context.Device, &memoryGetFdInfoKHR, out var vulkanImageFd).ThrowOnError();
- var renderFinished = context.RenderFinishedSemaphore;
- var submitInfo = new SubmitInfo
+ // 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(waitSemaphoresArray);
+ // var pipelineStageFlagsSpan = new ReadOnlySpan(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.AllGraphicsBit];
+ fixed (PipelineStageFlags* pPipelineStageFlags = pipelineStageFlags)
{
- SType = StructureType.SubmitInfo,
- CommandBufferCount = 1,
- PCommandBuffers = &commandBuffers,
- PSignalSemaphores = &renderFinished,
- SignalSemaphoreCount = 1
- };
+ ReadOnlySpan waitSemaphores =
+ [
+ imageRenderedSemaphore
+ ];
+ var submitInfo = new SubmitInfo
+ {
+ SType = StructureType.SubmitInfo,
+ CommandBufferCount = 1,
+ PCommandBuffers = &commandBuffer,
+ PSignalSemaphores = &imageExportedSemaphore,
+ SignalSemaphoreCount = 1,
+ PWaitSemaphores = initializationFrame ? null : &imageRenderedSemaphore,
+ WaitSemaphoreCount = initializationFrame ? 0u : 1u,
+ PWaitDstStageMask = initializationFrame ? null : pPipelineStageFlags
+ };
- context.Api.QueueSubmit(context.Queue, 1, &submitInfo, fence).ThrowOnError();
- context.Api.WaitForFences(context.Device, 1, &fence, true, ulong.MaxValue).ThrowOnError();
- context.Api.ResetFences(context.Device, 1, &fence).ThrowOnError();
+ // Console.WriteLine("Import 18");
+ _context.Api.QueueSubmit(_context.Queue, 1, &submitInfo, new Silk.NET.Vulkan.Fence(UIntPtr.Zero)).ThrowOnError();
+ }
- return new VkImage()
+ // Console.WriteLine("Import 19");
+ return new VulkanExportedImage
{
- Width = width,
- Height = height,
- Fd = vulkanFd,
- MemorySize = exportMemoryReqirements.Size
+ ImageExportedSemaphoreFd = imageExportedSemaphoreFd,
+ ImageRenderedSemaphoreFd = imageRenderedSemaphoreFd,
+ OrignalFd = imageFdDuplicate,
+ 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)
{
- Console.WriteLine(e.Message);
- Console.WriteLine(e.StackTrace);
+ // Console.WriteLine(e.Message);
+ // Console.WriteLine(e.StackTrace);
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)
{
var subresourceLayout = new SubresourceLayout
@@ -202,8 +291,8 @@ class VkRenderer
SharingMode = SharingMode.Exclusive,
InitialLayout = ImageLayout.Undefined
};
- context.Api.CreateImage(context.Device, &imageCreateInfo, null, out var image).ThrowOnError();
- context.Api.GetImageMemoryRequirements(context.Device, image, out var memoryReqirements);
+ _context.Api.CreateImage(_context.Device, &imageCreateInfo, null, out var image).ThrowOnError();
+ _context.Api.GetImageMemoryRequirements(_context.Device, image, out var memoryReqirements);
var importMemoryFdInfoKHR = new ImportMemoryFdInfoKHR
{
@@ -218,8 +307,8 @@ class VkRenderer
MemoryTypeIndex = checked((uint)FindMemoryType(memoryReqirements.MemoryTypeBits, MemoryPropertyFlags.DeviceLocalBit)),
PNext = &importMemoryFdInfoKHR,
};
- context.Api.AllocateMemory(context.Device, &memoryAllocateInfo, null, out var memory).ThrowOnError();
- context.Api.BindImageMemory(context.Device, image, memory, 0).ThrowOnError();
+ _context.Api.AllocateMemory(_context.Device, &memoryAllocateInfo, null, out var memory).ThrowOnError();
+ _context.Api.BindImageMemory(_context.Device, image, memory, 0).ThrowOnError();
return (image, memoryReqirements, memory);
}
@@ -250,8 +339,8 @@ class VkRenderer
SharingMode = SharingMode.Exclusive,
InitialLayout = ImageLayout.Undefined,
};
- context.Api.CreateImage(context.Device, &imageCreateInfo, null, out var image).ThrowOnError();
- context.Api.GetImageMemoryRequirements(context.Device, image, out var memoryReqirements);
+ _context.Api.CreateImage(_context.Device, &imageCreateInfo, null, out var image).ThrowOnError();
+ _context.Api.GetImageMemoryRequirements(_context.Device, image, out var memoryReqirements);
var exportMemoryFdInfoKHR = new ExportMemoryAllocateInfoKHR
{
@@ -265,15 +354,15 @@ class VkRenderer
MemoryTypeIndex = checked((uint)FindMemoryType(memoryReqirements.MemoryTypeBits, MemoryPropertyFlags.DeviceLocalBit)),
PNext = &exportMemoryFdInfoKHR,
};
- context.Api.AllocateMemory(context.Device, &exportAllocateInfo, null, out var memory).ThrowOnError();
- context.Api.BindImageMemory(context.Device, image, memory, 0).ThrowOnError();
+ _context.Api.AllocateMemory(_context.Device, &exportAllocateInfo, null, out var memory).ThrowOnError();
+ _context.Api.BindImageMemory(_context.Device, image, memory, 0).ThrowOnError();
return (image, memoryReqirements, memory);
}
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++)
if ((typeFilter & (1 << i)) != 0 && (memProps.MemoryTypes[i].PropertyFlags & properties) == properties)
return i;
@@ -299,7 +388,7 @@ class VkRenderer
}
};
- context.Api.CmdPipelineBarrier(
+ _context.Api.CmdPipelineBarrier(
cmd,
PipelineStageFlags.TopOfPipeBit,
PipelineStageFlags.TransferBit,
@@ -308,77 +397,56 @@ class VkRenderer
0, null,
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
{
+ 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 _logger;
private bool _initialized = false;
+ private bool _initializationFrame = true;
+
private Compositor? _compositor;
private CompositionSurfaceVisual? _visual;
private ICompositionGpuInterop? _gpuInterop;
- private CompositionDrawingSurface? Surface { get; set; }
+ private CompositionDrawingSurface? _surface;
+
+ private VulkanRenderer? _renerer;
+ private VulkanExportedImage? _latestImage;
+ private PresentedFrame? _lastFrame;
+
private bool _compositionRequested;
- private VkRenderer? _renerer;
- private VkImage? _latestImage;
private System.Timers.Timer? _updateTimer;
- public CameraView()
- { }
+ public CameraView(ILogger logger)
+ {
+ _logger = logger;
+ }
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
@@ -416,7 +484,7 @@ public partial class CameraView : Control
{
_updateTimer?.Stop();
_updateTimer?.Dispose();
- Surface?.Dispose();
+ _surface?.Dispose();
}
_initialized = false;
@@ -429,17 +497,18 @@ public partial class CameraView : Control
var selfVisual = ElementComposition.GetElementVisual(this)!;
_compositor = selfVisual.Compositor;
- Surface = _compositor.CreateDrawingSurface();
+ _surface = _compositor.CreateDrawingSurface();
_visual = _compositor.CreateSurfaceVisual();
- _visual.Surface = Surface;
+ _visual.Surface = _surface;
ElementComposition.SetElementChildVisual(this, _visual);
_gpuInterop = await _compositor.TryGetCompositionGpuInterop();
- _renerer = new VkRenderer();
+ _renerer = new VulkanRenderer();
_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);
}
- 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));
- imageRenderedSemaphore.ImportCompleted.ContinueWith(t =>
+ var imageExportedSemaphore = _gpuInterop!.ImportSemaphore(waitSemaphore);
+ imageExportedSemaphore.ImportCompleted.ContinueWith(t =>
{
- Console.WriteLine($"imageRenderedSemaphore.ImportCompleted {t.Status}");
- if (t.Exception is not null)
- {
- 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);
- }
- }
+ if (t.IsCompletedSuccessfully)
+ return;
+ _logger.LogError(t.Exception, "Error while imageExported semaphore import");
});
- var renderCompletedSemaphore = _gpuInterop!.ImportSemaphore(_renerer!.ExportSemaphore(true));
- renderCompletedSemaphore.ImportCompleted.ContinueWith(t =>
+ var imageRenderedSemaphore = _gpuInterop!.ImportSemaphore(signalSemaphore);
+ imageExportedSemaphore.ImportCompleted.ContinueWith(t =>
{
- Console.WriteLine($"renderCompletedSemaphore.ImportCompleted {t.Status}");
- if (t.Exception is not null)
- {
- 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);
- }
- }
+ if (t.IsCompletedSuccessfully)
+ return;
+ _logger.LogError(t.Exception, "Error while imageRendered semaphore import");
});
-
- Console.WriteLine("ImportImage");
var importedImage = _gpuInterop!.ImportImage(handle, properties);
- importedImage.ImportCompleted.ContinueWith(t =>
+ imageExportedSemaphore.ImportCompleted.ContinueWith(t =>
{
- Console.WriteLine($"importedImage.ImportCompleted {t.Status}");
- if (t.Exception is not null)
- {
- 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);
- }
- }
+ if (t.IsCompletedSuccessfully)
+ return;
+ _logger.LogError(t.Exception, "Error while image import");
});
+ var frame = new PresentedFrame
+ {
+ Image = importedImage,
+ Wait = imageExportedSemaphore,
+ Signal = imageRenderedSemaphore,
+ Vulkan = image
+ };
+
Dispatcher.UIThread.Invoke(async () =>
{
- await Surface!.UpdateWithSemaphoresAsync(importedImage, renderCompletedSemaphore, imageRenderedSemaphore)
- .ContinueWith((t) =>
- {
- Console.WriteLine($"UpdateWithSemaphoresAsync {t.Status}");
- if (t.Exception is not null)
- {
- Console.WriteLine($"Error while surface update: \n{t.Exception.Message}\n{t.Exception.StackTrace} ");
- foreach (var e in t.Exception.InnerExceptions)
- {
- Console.WriteLine(e.Message);
- Console.WriteLine(e.StackTrace);
- }
- }
- });
- }
- );
+ await _surface!.UpdateWithSemaphoresAsync(importedImage, imageExportedSemaphore, imageRenderedSemaphore).ContinueWith(t =>
+ {
+ _updateTimer?.Start();
+ _lastFrame?.DisposeAsync(_renerer);
+ _lastFrame = frame;
+ if (t.IsCompletedSuccessfully)
+ return;
+ _logger.LogError(t.Exception, "Error while image update");
+ });
+ });
}
private void OnComposition()
{
@@ -533,18 +581,32 @@ public partial class CameraView : Control
}
private void Update(FrameBuffer? frameBuffer = null, StreamConfiguration? streamConfiguration = null)
{
+ // Console.WriteLine("Update 1");
if (!_initialized || _compositor is null)
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;
}
if (_compositionRequested)
return;
-
_compositionRequested = true;
_compositor?.RequestCompositionUpdate(OnComposition);
}
diff --git a/GSS2.Test/Views/MainView.axaml b/GSS2.Test/Views/MainView.axaml
index 0f8bfee..be1af8b 100644
--- a/GSS2.Test/Views/MainView.axaml
+++ b/GSS2.Test/Views/MainView.axaml
@@ -5,6 +5,8 @@
xmlns:local="using:GSS2.Test.Views"
x:DataType="vm:MainViewModel"
x:Class="GSS2.Test.Views.MainView">
-
-
+
+
+
+
\ No newline at end of file
diff --git a/GSS2.Test/Views/ResourcesView.axaml b/GSS2.Test/Views/ResourcesView.axaml
index 98fc4c4..0b41203 100644
--- a/GSS2.Test/Views/ResourcesView.axaml
+++ b/GSS2.Test/Views/ResourcesView.axaml
@@ -11,7 +11,7 @@
Series="{Binding CpuUsageSeries}"
YAxes="{Binding CpuUsageSeriesYAxes}"
XAxes="{Binding CpuUsageSeriesXAxes}"
- Height="300"
+ Height="150"
ZoomMode="None"
EasingFunction="{x:Null}" />
@@ -44,39 +44,39 @@
diff --git a/GSS2.Vulkan/VulkanContext.cs b/GSS2.Vulkan/VulkanContext.cs
index f4196c7..c79def2 100644
--- a/GSS2.Vulkan/VulkanContext.cs
+++ b/GSS2.Vulkan/VulkanContext.cs
@@ -19,8 +19,13 @@ unsafe public class VulkanContext : IDisposable
public Device Device { get; init; }
public uint QueueFamilyIndex { get; init; }
public Queue Queue { get; init; }
- public Semaphore ImageAvailableSemaphore { get; init; }
- public Semaphore RenderFinishedSemaphore { 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)
{
@@ -30,42 +35,42 @@ unsafe public class VulkanContext : IDisposable
[
"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 instanceLayers =
[
-
+
];
List deviceExtensions =
[
"VK_KHR_external_memory",
"VK_KHR_external_memory_fd",
"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);
PhysicalDevice = FindPhysicalDevice(Api, Instance, deviceExtensions);
(Device, QueueFamilyIndex) = CreateDevice(Api, Instance, PhysicalDevice, deviceExtensions);
Queue = CreateQueue(Api, Device, QueueFamilyIndex);
- ImageAvailableSemaphore = CreateSemaphore(Api, Device);
- RenderFinishedSemaphore = CreateSemaphore(Api, Device);
- }
+ ImageExportedSemaphore = 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(Instance, Device, out var extension))
- throw new InvalidOperationException($"No {KhrExternalSemaphoreFd.ExtensionName} device extension");
-
- var info = new SemaphoreGetFdInfoKHR()
- {
- SType = StructureType.SemaphoreGetFDInfoKhr,
- Semaphore = semaphore,
- HandleType = ExternalSemaphoreHandleTypeFlags.OpaqueFDBit
- };
- extension.GetSemaphoreF(Device, in info, out var fd).ThrowOnError();
- return fd;
+ if (!Api.TryGetDeviceExtension(Instance, Device, out var khrExternalMemoryFd))
+ throw new Exception("KhrExternalMemoryFd import error");
+ KhrExternalMemoryFd = khrExternalMemoryFd;
+ if (!Api.TryGetDeviceExtension(Instance, Device, out var khrExternalSemaphoreFd))
+ throw new Exception("KhrExternalMemoryFd import error");
+ KhrExternalSemaphoreFd = khrExternalSemaphoreFd;
+ if (!Api.TryGetDeviceExtension(Instance, Device, out var khrExternalFenceFd))
+ throw new Exception("KhrExternalFenceFd import error");
+ KhrExternalFenceFd = khrExternalFenceFd;
}
private static Instance CreateInstance(Vk api, string applicationName, string engineName, List extentions, List layers)
@@ -186,6 +191,32 @@ unsafe public class VulkanContext : IDisposable
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)
{
@@ -195,8 +226,11 @@ unsafe public class VulkanContext : IDisposable
{
if (Api is null)
return;
- Api.DestroySemaphore(Device, ImageAvailableSemaphore, null);
- Api.DestroySemaphore(Device, RenderFinishedSemaphore, null);
+ 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;
}