|
@@ -8,6 +8,7 @@ using Avalonia.Platform;
|
|
|
using Avalonia.Vulkan;
|
|
|
using SharpDX.DXGI;
|
|
|
using Silk.NET.Vulkan;
|
|
|
+using Silk.NET.Vulkan.Extensions.EXT;
|
|
|
using Silk.NET.Vulkan.Extensions.KHR;
|
|
|
using SilkNetDemo;
|
|
|
using SkiaSharp;
|
|
@@ -45,6 +46,8 @@ public unsafe class VulkanImage : IDisposable
|
|
|
public ulong MemorySize { get; }
|
|
|
public uint CurrentLayout => (uint) _currentLayout;
|
|
|
|
|
|
+ private bool _hasIOSurface;
|
|
|
+
|
|
|
public VulkanImage(VulkanContext vk, uint format, PixelSize size,
|
|
|
bool exportable, IReadOnlyList<string> supportedHandleTypes)
|
|
|
{
|
|
@@ -75,10 +78,22 @@ public unsafe class VulkanImage : IDisposable
|
|
|
SType = StructureType.ExternalMemoryImageCreateInfo,
|
|
|
HandleTypes = handleType
|
|
|
};
|
|
|
+
|
|
|
+
|
|
|
+ var ioSurfaceCreateInfo = new ExportMetalObjectCreateInfoEXT
|
|
|
+ {
|
|
|
+ SType = StructureType.ExportMetalObjectCreateInfoExt,
|
|
|
+ ExportObjectType = ExportMetalObjectTypeFlagsEXT.IosurfaceBitExt
|
|
|
+ };
|
|
|
+
|
|
|
+ _hasIOSurface = exportable && RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
|
|
|
|
|
|
var imageCreateInfo = new ImageCreateInfo
|
|
|
{
|
|
|
- PNext = exportable ? &externalMemoryCreateInfo : null,
|
|
|
+ PNext = exportable ?
|
|
|
+ RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ?
|
|
|
+ &ioSurfaceCreateInfo :
|
|
|
+ &externalMemoryCreateInfo : null,
|
|
|
SType = StructureType.ImageCreateInfo,
|
|
|
ImageType = ImageType.Type2D,
|
|
|
Format = Format,
|
|
@@ -98,59 +113,64 @@ public unsafe class VulkanImage : IDisposable
|
|
|
Api
|
|
|
.CreateImage(_device, imageCreateInfo, null, out var image).ThrowOnError();
|
|
|
InternalHandle = image;
|
|
|
-
|
|
|
- Api.GetImageMemoryRequirements(_device, InternalHandle,
|
|
|
- out var memoryRequirements);
|
|
|
|
|
|
- var dedicatedAllocation = new MemoryDedicatedAllocateInfoKHR
|
|
|
- {
|
|
|
- SType = StructureType.MemoryDedicatedAllocateInfoKhr,
|
|
|
- Image = image
|
|
|
- };
|
|
|
-
|
|
|
- var fdExport = new ExportMemoryAllocateInfo
|
|
|
+ if (!exportable || !RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
|
|
{
|
|
|
- HandleTypes = handleType, SType = StructureType.ExportMemoryAllocateInfo,
|
|
|
- PNext = &dedicatedAllocation
|
|
|
- };
|
|
|
|
|
|
- ImportMemoryWin32HandleInfoKHR handleImport = default;
|
|
|
- if (handleType == ExternalMemoryHandleTypeFlags.D3D11TextureBit && exportable)
|
|
|
- {
|
|
|
- var d3dDevice = vk.D3DDevice ?? throw new NotSupportedException("Vulkan D3DDevice wasn't created");
|
|
|
- _d3dTexture2D = D3DMemoryHelper.CreateMemoryHandle(d3dDevice, size, Format);
|
|
|
- using var dxgi = _d3dTexture2D.QueryInterface<SharpDX.DXGI.Resource1>();
|
|
|
+ Api.GetImageMemoryRequirements(_device, InternalHandle,
|
|
|
+ out var memoryRequirements);
|
|
|
|
|
|
- handleImport = new ImportMemoryWin32HandleInfoKHR
|
|
|
+ var dedicatedAllocation = new MemoryDedicatedAllocateInfoKHR
|
|
|
{
|
|
|
- PNext = &dedicatedAllocation,
|
|
|
- SType = StructureType.ImportMemoryWin32HandleInfoKhr,
|
|
|
- HandleType = ExternalMemoryHandleTypeFlags.D3D11TextureBit,
|
|
|
- Handle = dxgi.CreateSharedHandle(null, SharedResourceFlags.Read | SharedResourceFlags.Write),
|
|
|
+ SType = StructureType.MemoryDedicatedAllocateInfoKhr, Image = image
|
|
|
};
|
|
|
- }
|
|
|
|
|
|
- var memoryAllocateInfo = new MemoryAllocateInfo
|
|
|
- {
|
|
|
- PNext =
|
|
|
- exportable ? handleImport.Handle != IntPtr.Zero ? &handleImport : &fdExport : null,
|
|
|
- SType = StructureType.MemoryAllocateInfo,
|
|
|
- AllocationSize = memoryRequirements.Size,
|
|
|
- MemoryTypeIndex = (uint)VulkanMemoryHelper.FindSuitableMemoryTypeIndex(
|
|
|
- Api,
|
|
|
- _physicalDevice,
|
|
|
- memoryRequirements.MemoryTypeBits, MemoryPropertyFlags.DeviceLocalBit)
|
|
|
- };
|
|
|
+ var fdExport = new ExportMemoryAllocateInfo
|
|
|
+ {
|
|
|
+ HandleTypes = handleType,
|
|
|
+ SType = StructureType.ExportMemoryAllocateInfo,
|
|
|
+ PNext = &dedicatedAllocation
|
|
|
+ };
|
|
|
|
|
|
- Api.AllocateMemory(_device, memoryAllocateInfo, null,
|
|
|
- out var imageMemory).ThrowOnError();
|
|
|
+ ImportMemoryWin32HandleInfoKHR handleImport = default;
|
|
|
+ if (handleType == ExternalMemoryHandleTypeFlags.D3D11TextureBit && exportable)
|
|
|
+ {
|
|
|
+ var d3dDevice = vk.D3DDevice ?? throw new NotSupportedException("Vulkan D3DDevice wasn't created");
|
|
|
+ _d3dTexture2D = D3DMemoryHelper.CreateMemoryHandle(d3dDevice, size, Format);
|
|
|
+ using var dxgi = _d3dTexture2D.QueryInterface<SharpDX.DXGI.Resource1>();
|
|
|
|
|
|
- _imageMemory = imageMemory;
|
|
|
-
|
|
|
-
|
|
|
- MemorySize = memoryRequirements.Size;
|
|
|
+ handleImport = new ImportMemoryWin32HandleInfoKHR
|
|
|
+ {
|
|
|
+ PNext = &dedicatedAllocation,
|
|
|
+ SType = StructureType.ImportMemoryWin32HandleInfoKhr,
|
|
|
+ HandleType = ExternalMemoryHandleTypeFlags.D3D11TextureBit,
|
|
|
+ Handle = dxgi.CreateSharedHandle(null, SharedResourceFlags.Read | SharedResourceFlags.Write),
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ var memoryAllocateInfo = new MemoryAllocateInfo
|
|
|
+ {
|
|
|
+ PNext =
|
|
|
+ exportable ? handleImport.Handle != IntPtr.Zero ? &handleImport : &fdExport : null,
|
|
|
+ SType = StructureType.MemoryAllocateInfo,
|
|
|
+ AllocationSize = memoryRequirements.Size,
|
|
|
+ MemoryTypeIndex = (uint)VulkanMemoryHelper.FindSuitableMemoryTypeIndex(
|
|
|
+ Api,
|
|
|
+ _physicalDevice,
|
|
|
+ memoryRequirements.MemoryTypeBits, MemoryPropertyFlags.DeviceLocalBit)
|
|
|
+ };
|
|
|
+
|
|
|
+ Api.AllocateMemory(_device, memoryAllocateInfo, null,
|
|
|
+ out var imageMemory).ThrowOnError();
|
|
|
+
|
|
|
+ _imageMemory = imageMemory;
|
|
|
+
|
|
|
+
|
|
|
+ MemorySize = memoryRequirements.Size;
|
|
|
+
|
|
|
+ Api.BindImageMemory(_device, InternalHandle, _imageMemory, 0).ThrowOnError();
|
|
|
+ }
|
|
|
|
|
|
- Api.BindImageMemory(_device, InternalHandle, _imageMemory, 0).ThrowOnError();
|
|
|
var componentMapping = new ComponentMapping(
|
|
|
ComponentSwizzle.Identity,
|
|
|
ComponentSwizzle.Identity,
|
|
@@ -209,6 +229,26 @@ public unsafe class VulkanImage : IDisposable
|
|
|
ext.GetMemoryWin32Handle(_device, info, out var fd).ThrowOnError();
|
|
|
return fd;
|
|
|
}
|
|
|
+
|
|
|
+ public IntPtr ExportIOSurface()
|
|
|
+ {
|
|
|
+ if (!Api.TryGetDeviceExtension<ExtMetalObjects>(_instance, _device, out var ext))
|
|
|
+ throw new InvalidOperationException();
|
|
|
+ var surfaceExport = new ExportMetalIOSurfaceInfoEXT
|
|
|
+ {
|
|
|
+ SType = StructureType.ExportMetalIOSurfaceInfoExt,
|
|
|
+ Image = InternalHandle
|
|
|
+ };
|
|
|
+ var export = new ExportMetalObjectsInfoEXT()
|
|
|
+ {
|
|
|
+ SType = StructureType.ExportMetalObjectsInfoExt,
|
|
|
+ PNext = &surfaceExport
|
|
|
+ };
|
|
|
+ ext.ExportMetalObjects(_device, ref export);
|
|
|
+ if (surfaceExport.IoSurface == IntPtr.Zero)
|
|
|
+ throw new Exception("Unable to export IOSurfaceRef");
|
|
|
+ return surfaceExport.IoSurface;
|
|
|
+ }
|
|
|
|
|
|
public IPlatformHandle Export()
|
|
|
{
|
|
@@ -225,6 +265,9 @@ public unsafe class VulkanImage : IDisposable
|
|
|
return new PlatformHandle(ExportOpaqueNtHandle(),
|
|
|
KnownPlatformGraphicsExternalImageHandleTypes.VulkanOpaqueNtHandle);
|
|
|
}
|
|
|
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
|
|
+ return new PlatformHandle(ExportIOSurface(),
|
|
|
+ KnownPlatformGraphicsExternalImageHandleTypes.IOSurfaceRef);
|
|
|
else
|
|
|
return new PlatformHandle(new IntPtr(ExportFd()),
|
|
|
KnownPlatformGraphicsExternalImageHandleTypes.VulkanOpaquePosixFileDescriptor);
|
|
@@ -281,6 +324,30 @@ public unsafe class VulkanImage : IDisposable
|
|
|
|
|
|
public void SaveTexture(string path)
|
|
|
{
|
|
|
+ if (_vk.GrContext == null)
|
|
|
+ {
|
|
|
+ if (_hasIOSurface)
|
|
|
+ {
|
|
|
+ var surf = ExportIOSurface();
|
|
|
+ if (NativeMethods.IOSurfaceLock(surf, 0, IntPtr.Zero) != 0)
|
|
|
+ throw new Exception("IOSurfaceLock failed");
|
|
|
+ var w = (int)NativeMethods.IOSurfaceGetWidth(surf);
|
|
|
+ var h = (int)NativeMethods.IOSurfaceGetHeight(surf);
|
|
|
+ var sstride = NativeMethods.IOSurfaceGetBytesPerRow(surf);
|
|
|
+
|
|
|
+ var pSurface = NativeMethods.IOSurfaceGetBaseAddress(surf);
|
|
|
+ using var b = new Avalonia.Media.Imaging.Bitmap(PixelFormat.Bgra8888,
|
|
|
+ AlphaFormat.Premul, pSurface, new PixelSize(w, h),
|
|
|
+ new Vector(96, 96), (int)sstride);
|
|
|
+ b.Save(path);
|
|
|
+
|
|
|
+ NativeMethods.IOSurfaceUnlock(surf, 0, IntPtr.Zero);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ throw new NotSupportedException("Need skia to dump textures, sorry");
|
|
|
+ }
|
|
|
+
|
|
|
_vk.GrContext.ResetContext();
|
|
|
var _image = this;
|
|
|
var imageInfo = new GRVkImageInfo()
|