Browse Source

Use NT shared handles for Vulkan interop on Windows

pull/10333/head
kekekeks 3 years ago
parent
commit
fc0ddcb320
  1. 2
      samples/GpuInterop/VulkanDemo/D3DMemoryHelper.cs
  2. 2
      samples/GpuInterop/VulkanDemo/VulkanContext.cs
  3. 30
      samples/GpuInterop/VulkanDemo/VulkanImage.cs
  4. 40
      src/Windows/Avalonia.Win32/DirectX/directx.idl
  5. 14
      src/Windows/Avalonia.Win32/OpenGl/Angle/AngleExternalObjectsFeature.cs

2
samples/GpuInterop/VulkanDemo/D3DMemoryHelper.cs

@ -47,7 +47,7 @@ public class D3DMemoryHelper
MipLevels = 1, MipLevels = 1,
SampleDescription = new SampleDescription { Count = 1, Quality = 0 }, SampleDescription = new SampleDescription { Count = 1, Quality = 0 },
CpuAccessFlags = default, CpuAccessFlags = default,
OptionFlags = ResourceOptionFlags.SharedKeyedmutex, OptionFlags = ResourceOptionFlags.SharedKeyedmutex|ResourceOptionFlags.SharedNthandle,
BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource
}); });
} }

2
samples/GpuInterop/VulkanDemo/VulkanContext.cs

@ -173,7 +173,7 @@ public unsafe class VulkanContext : IDisposable
api.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, ref queueFamilyCount, familyProperties); api.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, ref queueFamilyCount, familyProperties);
for (uint queueFamilyIndex = 0; queueFamilyIndex < queueFamilyCount; queueFamilyIndex++) for (uint queueFamilyIndex = 0; queueFamilyIndex < queueFamilyCount; queueFamilyIndex++)
{ {
var family = familyProperties[c]; var family = familyProperties[queueFamilyIndex];
if (!family.QueueFlags.HasAllFlags(QueueFlags.GraphicsBit)) if (!family.QueueFlags.HasAllFlags(QueueFlags.GraphicsBit))
continue; continue;

30
samples/GpuInterop/VulkanDemo/VulkanImage.cs

@ -4,10 +4,13 @@ using System.Runtime.InteropServices;
using Avalonia; using Avalonia;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Vulkan; using Avalonia.Vulkan;
using SharpDX.DXGI;
using Silk.NET.Vulkan; using Silk.NET.Vulkan;
using Silk.NET.Vulkan.Extensions.KHR; using Silk.NET.Vulkan.Extensions.KHR;
using SilkNetDemo; using SilkNetDemo;
using SkiaSharp; using SkiaSharp;
using Device = Silk.NET.Vulkan.Device;
using Format = Silk.NET.Vulkan.Format;
namespace GpuInterop.VulkanDemo; namespace GpuInterop.VulkanDemo;
@ -24,7 +27,6 @@ public unsafe class VulkanImage : IDisposable
private ImageView? _imageView { get; set; } private ImageView? _imageView { get; set; }
private DeviceMemory _imageMemory { get; set; } private DeviceMemory _imageMemory { get; set; }
private SharpDX.Direct3D11.Texture2D? _d3dTexture2D; private SharpDX.Direct3D11.Texture2D? _d3dTexture2D;
private IntPtr _win32ShareHandle;
internal Image? InternalHandle { get; private set; } internal Image? InternalHandle { get; private set; }
internal Format Format { get; } internal Format Format { get; }
@ -108,14 +110,14 @@ public unsafe class VulkanImage : IDisposable
if (exportable && RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) if (exportable && RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{ {
_d3dTexture2D = D3DMemoryHelper.CreateMemoryHandle(vk.D3DDevice, size, Format); _d3dTexture2D = D3DMemoryHelper.CreateMemoryHandle(vk.D3DDevice, size, Format);
using var dxgi = _d3dTexture2D.QueryInterface<SharpDX.DXGI.Resource>(); using var dxgi = _d3dTexture2D.QueryInterface<SharpDX.DXGI.Resource1>();
_win32ShareHandle = dxgi.SharedHandle;
handleImport = new ImportMemoryWin32HandleInfoKHR handleImport = new ImportMemoryWin32HandleInfoKHR
{ {
PNext = &dedicatedAllocation, PNext = &dedicatedAllocation,
SType = StructureType.ImportMemoryWin32HandleInfoKhr, SType = StructureType.ImportMemoryWin32HandleInfoKhr,
HandleType = ExternalMemoryHandleTypeFlags.D3D11TextureKmtBit, HandleType = ExternalMemoryHandleTypeFlags.D3D11TextureBit,
Handle = _win32ShareHandle, Handle = dxgi.CreateSharedHandle(null, SharedResourceFlags.Read | SharedResourceFlags.Write),
}; };
} }
@ -185,11 +187,19 @@ public unsafe class VulkanImage : IDisposable
return fd; return fd;
} }
public IPlatformHandle Export() => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? public IPlatformHandle Export()
new PlatformHandle(_win32ShareHandle, {
KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureGlobalSharedHandle) : if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
new PlatformHandle(new IntPtr(ExportFd()), {
KnownPlatformGraphicsExternalImageHandleTypes.VulkanOpaquePosixFileDescriptor); using var dxgi = _d3dTexture2D!.QueryInterface<Resource1>();
return new PlatformHandle(
dxgi.CreateSharedHandle(null, SharedResourceFlags.Read | SharedResourceFlags.Write),
KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureNtHandle);
}
else
return new PlatformHandle(new IntPtr(ExportFd()),
KnownPlatformGraphicsExternalImageHandleTypes.VulkanOpaquePosixFileDescriptor);
}
public ImageTiling Tiling => ImageTiling.Optimal; public ImageTiling Tiling => ImageTiling.Optimal;

40
src/Windows/Avalonia.Win32/DirectX/directx.idl

@ -36,6 +36,8 @@
@clr-map DXGI_SHARED_RESOURCE void* @clr-map DXGI_SHARED_RESOURCE void*
@clr-map LUID ulong @clr-map LUID ulong
@clr-map LPSTR ushort* @clr-map LPSTR ushort*
@clr-map LPWSTR ushort*
@clr-map LPCWSTR ushort*
enum DXGI_FORMAT enum DXGI_FORMAT
@ -501,6 +503,44 @@ interface ID3D11Device : IUnknown
UINT GetExceptionMode(); UINT GetExceptionMode();
} }
[uuid(a04bfb29-08ef-43d6-a49c-a9bdbdcbe686)]
interface ID3D11Device1 : ID3D11Device
{
void GetImmediateContext1( void** ppImmediateContext );
HRESULT CreateDeferredContext1(
UINT ContextFlags, // Reserved parameter; must be 0
[out, retval] IUnknown** ppDeferredContext );
HRESULT CreateBlendState1(
void* pBlendStateDesc,
[out, retval] IUnknown** ppBlendState );
HRESULT CreateRasterizerState1(
void* pRasterizerDesc,
[out, retval] IUnknown** ppRasterizerState );
HRESULT CreateDeviceContextState(
UINT Flags,
void* pFeatureLevels,
UINT FeatureLevels,
UINT SDKVersion,
GUID* EmulatedInterface,
void* pChosenFeatureLevel,
[out, retval] IUnknown** ppContextState);
HRESULT OpenSharedResource1(
IntPtr hResource,
Guid* ReturnedInterface,
[out, retval] IUnknown** ppResource);
HRESULT OpenSharedResourceByName(
LPCWSTR lpName,
DWORD dwDesiredAccess,
REFIID returnedInterface,
void** ppResource);
};
[uuid( 6f15aaf2-d208-4e89-9ab4-489535d34f9c)] [uuid( 6f15aaf2-d208-4e89-9ab4-489535d34f9c)]
interface ID3D11Texture2D : IUnknown interface ID3D11Texture2D : IUnknown

14
src/Windows/Avalonia.Win32/OpenGl/Angle/AngleExternalObjectsFeature.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using Avalonia.Controls.Documents; using Avalonia.Controls.Documents;
using Avalonia.OpenGL; using Avalonia.OpenGL;
@ -15,12 +16,14 @@ internal class AngleExternalObjectsFeature : IGlContextExternalObjectsFeature, I
{ {
private readonly EglContext _context; private readonly EglContext _context;
private readonly ID3D11Device _device; private readonly ID3D11Device _device;
private readonly ID3D11Device1 _device1;
public AngleExternalObjectsFeature(EglContext context) public AngleExternalObjectsFeature(EglContext context)
{ {
_context = context; _context = context;
var angle = (AngleWin32EglDisplay)context.Display; var angle = (AngleWin32EglDisplay)context.Display;
_device = MicroComRuntime.CreateProxyFor<ID3D11Device>(angle.GetDirect3DDevice(), false).CloneReference(); _device = MicroComRuntime.CreateProxyFor<ID3D11Device>(angle.GetDirect3DDevice(), false).CloneReference();
_device1 = _device.QueryInterface<ID3D11Device1>();
using var dxgiDevice = _device.QueryInterface<IDXGIDevice>(); using var dxgiDevice = _device.QueryInterface<IDXGIDevice>();
using var adapter = dxgiDevice.Adapter; using var adapter = dxgiDevice.Adapter;
DeviceLuid = BitConverter.GetBytes(adapter.Desc.AdapterLuid); DeviceLuid = BitConverter.GetBytes(adapter.Desc.AdapterLuid);
@ -28,7 +31,8 @@ internal class AngleExternalObjectsFeature : IGlContextExternalObjectsFeature, I
public IReadOnlyList<string> SupportedImportableExternalImageTypes { get; } = new[] public IReadOnlyList<string> SupportedImportableExternalImageTypes { get; } = new[]
{ {
KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureGlobalSharedHandle KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureGlobalSharedHandle,
KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureNtHandle,
}; };
public IReadOnlyList<string> SupportedExportableExternalImageTypes => SupportedImportableExternalImageTypes; public IReadOnlyList<string> SupportedExportableExternalImageTypes => SupportedImportableExternalImageTypes;
@ -72,13 +76,17 @@ internal class AngleExternalObjectsFeature : IGlContextExternalObjectsFeature, I
public unsafe IGlExternalImageTexture ImportImage(IPlatformHandle handle, PlatformGraphicsExternalImageProperties properties) public unsafe IGlExternalImageTexture ImportImage(IPlatformHandle handle, PlatformGraphicsExternalImageProperties properties)
{ {
if (handle.HandleDescriptor != KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureGlobalSharedHandle) if (!SupportedImportableExternalImageTypes.Contains(handle.HandleDescriptor))
throw new NotSupportedException("Unsupported external memory type"); throw new NotSupportedException("Unsupported external memory type");
using (_context.EnsureCurrent()) using (_context.EnsureCurrent())
{ {
var guid = MicroComRuntime.GetGuidFor(typeof(ID3D11Texture2D)); var guid = MicroComRuntime.GetGuidFor(typeof(ID3D11Texture2D));
using var opened = _device.OpenSharedResource(handle.Handle, &guid); using var opened =
handle.HandleDescriptor ==
KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureGlobalSharedHandle ?
_device.OpenSharedResource(handle.Handle, &guid) :
_device1.OpenSharedResource1(handle.Handle, &guid);
using var texture = opened.QueryInterface<ID3D11Texture2D>(); using var texture = opened.QueryInterface<ID3D11Texture2D>();
return new AngleExternalMemoryD3D11Texture2D(_context, texture, properties); return new AngleExternalMemoryD3D11Texture2D(_context, texture, properties);
} }

Loading…
Cancel
Save