Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vulkan backend #12737

Merged
merged 10 commits into from
Apr 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Avalonia.Desktop.slnf
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"src\\Avalonia.MicroCom\\Avalonia.MicroCom.csproj",
"src\\Avalonia.Native\\Avalonia.Native.csproj",
"src\\Avalonia.OpenGL\\Avalonia.OpenGL.csproj",
"src\\Avalonia.Vulkan\\Avalonia.Vulkan.csproj",
"src\\Avalonia.ReactiveUI\\Avalonia.ReactiveUI.csproj",
"src\\Avalonia.Remote.Protocol\\Avalonia.Remote.Protocol.csproj",
"src\\Avalonia.Themes.Fluent\\Avalonia.Themes.Fluent.csproj",
Expand Down
6 changes: 6 additions & 0 deletions Avalonia.sln
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnloadableAssemblyLoadConte
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnloadableAssemblyLoadContextPlug", "samples\UnloadableAssemblyLoadContext\UnloadableAssemblyLoadContextPlug\UnloadableAssemblyLoadContextPlug.csproj", "{DA5F1FF9-4259-4C54-B443-85CFA226EE6A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Vulkan", "src\Avalonia.Vulkan\Avalonia.Vulkan.csproj", "{3E2DE2B6-13BC-4C27-BCB9-A423B86CAF77}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.RenderTests.WpfCompare", "tests\Avalonia.RenderTests.WpfCompare\Avalonia.RenderTests.WpfCompare.csproj", "{9AE1B827-21AC-4063-AB22-C8804B7F931E}"
EndProject
Global
Expand Down Expand Up @@ -676,6 +678,10 @@ Global
{60B4ED1F-ECFA-453B-8A70-1788261C8355}.Debug|Any CPU.Build.0 = Debug|Any CPU
{60B4ED1F-ECFA-453B-8A70-1788261C8355}.Release|Any CPU.ActiveCfg = Release|Any CPU
{60B4ED1F-ECFA-453B-8A70-1788261C8355}.Release|Any CPU.Build.0 = Release|Any CPU
{3E2DE2B6-13BC-4C27-BCB9-A423B86CAF77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3E2DE2B6-13BC-4C27-BCB9-A423B86CAF77}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3E2DE2B6-13BC-4C27-BCB9-A423B86CAF77}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3E2DE2B6-13BC-4C27-BCB9-A423B86CAF77}.Release|Any CPU.Build.0 = Release|Any CPU
{B0FD6A48-FBAB-4676-B36A-DE76B0922B12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B0FD6A48-FBAB-4676-B36A-DE76B0922B12}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B0FD6A48-FBAB-4676-B36A-DE76B0922B12}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand Down
3 changes: 2 additions & 1 deletion Avalonia.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,5 @@
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EFeature_002EServices_002EDaemon_002ESettings_002EMigration_002ESwaWarningsModeSettingsMigrate/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Activatable/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Avalonia/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Fcitx/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Fcitx/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=swapchain/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
1 change: 1 addition & 0 deletions build/CoreLibraries.props
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj" />
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.OpenGL/Avalonia.OpenGL.csproj" />
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Metal/Avalonia.Metal.csproj" />
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Vulkan/Avalonia.Vulkan.csproj" />
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Dialogs/Avalonia.Dialogs.csproj" />
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Markup/Avalonia.Markup/Avalonia.Markup.csproj" />
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj" />
Expand Down
12 changes: 10 additions & 2 deletions samples/ControlCatalog.NetCore/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
using Avalonia.LogicalTree;
using Avalonia.Rendering.Composition;
using Avalonia.Threading;

using Avalonia.Vulkan;
using ControlCatalog.Pages;

namespace ControlCatalog.NetCore
Expand Down Expand Up @@ -133,7 +133,15 @@ public static AppBuilder BuildAvaloniaApp()
{
EnableMultiTouch = true,
UseDBusMenu = true,
EnableIme = true
EnableIme = true,
})

.With(new VulkanOptions
{
VulkanInstanceCreationOptions = new ()
{
UseDebug = true
}
})
.With(new CompositionOptions()
{
Expand Down
20 changes: 19 additions & 1 deletion samples/GpuInterop/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
global using System.Reactive.Disposables;
using Avalonia;
using Avalonia.Logging;
using Avalonia.Vulkan;

namespace GpuInterop
{
public class Program
Expand All @@ -10,6 +13,21 @@ static void Main(string[] args) => BuildAvaloniaApp()
public static AppBuilder BuildAvaloniaApp() =>
AppBuilder.Configure<App>()
.UsePlatformDetect()
.LogToTrace();
.With(new Win32PlatformOptions
{
RenderingMode = new []
{
Win32RenderingMode.Vulkan
}
})
.With(new X11PlatformOptions(){RenderingMode =new[] { X11RenderingMode.Vulkan } })
.With(new VulkanOptions()
{
VulkanInstanceCreationOptions = new VulkanInstanceCreationOptions()
{
UseDebug = true
}
})
.LogToTrace(LogEventLevel.Debug, "Vulkan");
}
}
2 changes: 1 addition & 1 deletion samples/GpuInterop/VulkanDemo/VulkanContent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ private unsafe void CreateTemporalObjects(PixelSize size)
Matrix4x4.CreatePerspectiveFieldOfView((float)(Math.PI / 4), (float)size.Width / size.Height,
0.01f, 1000);

_colorAttachment = new VulkanImage(_context, (uint)Format.R8G8B8A8Unorm, size, false);
_colorAttachment = new VulkanImage(_context, (uint)Format.R8G8B8A8Unorm, size, false, Array.Empty<string>());
CreateDepthAttachment(size);

var api = _context.Api;
Expand Down
9 changes: 7 additions & 2 deletions samples/GpuInterop/VulkanDemo/VulkanContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,10 @@ public static (VulkanContext? result, string info) TryCreate(ICompositionGpuInte

if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
if (!gpuInterop.SupportedImageHandleTypes.Contains(KnownPlatformGraphicsExternalImageHandleTypes
if (!(gpuInterop.SupportedImageHandleTypes.Contains(KnownPlatformGraphicsExternalImageHandleTypes
.D3D11TextureGlobalSharedHandle)
|| gpuInterop.SupportedImageHandleTypes.Contains(KnownPlatformGraphicsExternalImageHandleTypes
.VulkanOpaqueNtHandle))
)
return (null, "Image sharing is not supported by the current backend");
requireDeviceExtensions.Add(KhrExternalMemoryWin32.ExtensionName);
Expand Down Expand Up @@ -240,10 +242,13 @@ public static (VulkanContext? result, string info) TryCreate(ICompositionGpuInte
}
});



D3DDevice? d3dDevice = null;
if (physicalDeviceIDProperties.DeviceLuidvalid &&
RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
RuntimeInformation.IsOSPlatform(OSPlatform.Windows) &&
!gpuInterop.SupportedImageHandleTypes.Contains(KnownPlatformGraphicsExternalImageHandleTypes.VulkanOpaqueNtHandle)
)
d3dDevice = D3DMemoryHelper.CreateDeviceByLuid(
new Span<byte>(physicalDeviceIDProperties.DeviceLuid, 8));

Expand Down
76 changes: 52 additions & 24 deletions samples/GpuInterop/VulkanDemo/VulkanImage.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using Avalonia;
using Avalonia.Platform;
Expand Down Expand Up @@ -44,7 +46,7 @@ public unsafe class VulkanImage : IDisposable
public uint CurrentLayout => (uint) _currentLayout;

public VulkanImage(VulkanContext vk, uint format, PixelSize size,
bool exportable, uint mipLevels = 0)
bool exportable, IReadOnlyList<string> supportedHandleTypes)
{
_vk = vk;
_instance = vk.Instance;
Expand All @@ -62,8 +64,12 @@ public VulkanImage(VulkanContext vk, uint format, PixelSize size,
//MipLevels = MipLevels != 0 ? MipLevels : (uint)Math.Floor(Math.Log(Math.Max(Size.Width, Size.Height), 2));

var handleType = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ?
ExternalMemoryHandleTypeFlags.D3D11TextureBit :
(supportedHandleTypes.Contains(KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureNtHandle)
&& !supportedHandleTypes.Contains(KnownPlatformGraphicsExternalImageHandleTypes.VulkanOpaqueNtHandle) ?
ExternalMemoryHandleTypeFlags.D3D11TextureBit :
ExternalMemoryHandleTypeFlags.OpaqueWin32Bit) :
ExternalMemoryHandleTypeFlags.OpaqueFDBit;

var externalMemoryCreateInfo = new ExternalMemoryImageCreateInfo
{
SType = StructureType.ExternalMemoryImageCreateInfo,
Expand Down Expand Up @@ -96,35 +102,37 @@ public VulkanImage(VulkanContext vk, uint format, PixelSize size,
Api.GetImageMemoryRequirements(_device, InternalHandle,
out var memoryRequirements);


var fdExport = new ExportMemoryAllocateInfo
{
HandleTypes = handleType, SType = StructureType.ExportMemoryAllocateInfo
};
var dedicatedAllocation = new MemoryDedicatedAllocateInfoKHR
{
SType = StructureType.MemoryDedicatedAllocateInfoKhr,
Image = image
};

var fdExport = new ExportMemoryAllocateInfo
{
HandleTypes = handleType, SType = StructureType.ExportMemoryAllocateInfo,
PNext = &dedicatedAllocation
};

ImportMemoryWin32HandleInfoKHR handleImport = default;
if (exportable && RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
if (handleType == ExternalMemoryHandleTypeFlags.D3D11TextureBit && exportable)
{
_d3dTexture2D = D3DMemoryHelper.CreateMemoryHandle(vk.D3DDevice!, size, Format);
using var dxgi = _d3dTexture2D.QueryInterface<SharpDX.DXGI.Resource1>();
handleImport = new ImportMemoryWin32HandleInfoKHR
{
PNext = &dedicatedAllocation,
SType = StructureType.ImportMemoryWin32HandleInfoKhr,
HandleType = ExternalMemoryHandleTypeFlags.D3D11TextureBit,
Handle = dxgi.CreateSharedHandle(null, SharedResourceFlags.Read | SharedResourceFlags.Write),
};
_d3dTexture2D = D3DMemoryHelper.CreateMemoryHandle(vk.D3DDevice, size, Format);
using var dxgi = _d3dTexture2D.QueryInterface<SharpDX.DXGI.Resource1>();

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 ? RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? &handleImport : &fdExport : null,
exportable ? handleImport.Handle != IntPtr.Zero ? &handleImport : &fdExport : null,
SType = StructureType.MemoryAllocateInfo,
AllocationSize = memoryRequirements.Size,
MemoryTypeIndex = (uint)VulkanMemoryHelper.FindSuitableMemoryTypeIndex(
Expand Down Expand Up @@ -187,14 +195,34 @@ public int ExportFd()
return fd;
}

public IntPtr ExportOpaqueNtHandle()
{
if (!Api.TryGetDeviceExtension<KhrExternalMemoryWin32>(_instance, _device, out var ext))
throw new InvalidOperationException();
var info = new MemoryGetWin32HandleInfoKHR()
{
Memory = _imageMemory,
SType = StructureType.MemoryGetWin32HandleInfoKhr,
HandleType = ExternalMemoryHandleTypeFlags.OpaqueWin32Bit
};
ext.GetMemoryWin32Handle(_device, info, out var fd).ThrowOnError();
return fd;
}

public IPlatformHandle Export()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
using var dxgi = _d3dTexture2D!.QueryInterface<Resource1>();
return new PlatformHandle(
dxgi.CreateSharedHandle(null, SharedResourceFlags.Read | SharedResourceFlags.Write),
KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureNtHandle);
if (_d3dTexture2D != null)
{
using var dxgi = _d3dTexture2D!.QueryInterface<Resource1>();
return new PlatformHandle(
dxgi.CreateSharedHandle(null, SharedResourceFlags.Read | SharedResourceFlags.Write),
KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureNtHandle);
}

return new PlatformHandle(ExportOpaqueNtHandle(),
KnownPlatformGraphicsExternalImageHandleTypes.VulkanOpaqueNtHandle);
}
else
return new PlatformHandle(new IntPtr(ExportFd()),
Expand All @@ -203,7 +231,7 @@ public IPlatformHandle Export()

public ImageTiling Tiling => ImageTiling.Optimal;


public bool IsDirectXBacked => _d3dTexture2D != null;

internal void TransitionLayout(CommandBuffer commandBuffer,
ImageLayout fromLayout, AccessFlags fromAccessFlags,
Expand Down
32 changes: 30 additions & 2 deletions samples/GpuInterop/VulkanDemo/VulkanSemaphorePair.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using System.Runtime.InteropServices;
using Avalonia.Platform;
using Silk.NET.Vulkan;
using Silk.NET.Vulkan.Extensions.KHR;
using SilkNetDemo;
Expand All @@ -16,7 +18,9 @@ public unsafe VulkanSemaphorePair(VulkanContext resources, bool exportable)
var semaphoreExportInfo = new ExportSemaphoreCreateInfo
{
SType = StructureType.ExportSemaphoreCreateInfo,
HandleTypes = ExternalSemaphoreHandleTypeFlags.OpaqueFDBit
HandleTypes = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ?
ExternalSemaphoreHandleTypeFlags.OpaqueWin32Bit :
ExternalSemaphoreHandleTypeFlags.OpaqueFDBit
};

var semaphoreCreateInfo = new SemaphoreCreateInfo
Expand Down Expand Up @@ -46,6 +50,30 @@ public int ExportFd(bool renderFinished)
ext.GetSemaphoreF(_resources.Device, info, out var fd).ThrowOnError();
return fd;
}

public IntPtr ExportWin32(bool renderFinished)
{
if (!_resources.Api.TryGetDeviceExtension<KhrExternalSemaphoreWin32>(_resources.Instance, _resources.Device,
out var ext))
throw new InvalidOperationException();
var info = new SemaphoreGetWin32HandleInfoKHR()
{
SType = StructureType.SemaphoreGetWin32HandleInfoKhr,
Semaphore = renderFinished ? RenderFinishedSemaphore : ImageAvailableSemaphore,
HandleType = ExternalSemaphoreHandleTypeFlags.OpaqueWin32Bit
};
ext.GetSemaphoreWin32Handle(_resources.Device, info, out var fd).ThrowOnError();
return fd;
}

public IPlatformHandle Export(bool renderFinished)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return new PlatformHandle(ExportWin32(renderFinished),
KnownPlatformGraphicsExternalSemaphoreHandleTypes.VulkanOpaqueNtHandle);
return new PlatformHandle(new IntPtr(ExportFd(renderFinished)),
KnownPlatformGraphicsExternalSemaphoreHandleTypes.VulkanOpaquePosixFileDescriptor);
}

internal Semaphore ImageAvailableSemaphore { get; }
internal Semaphore RenderFinishedSemaphore { get; }
Expand All @@ -55,4 +83,4 @@ public unsafe void Dispose()
_resources.Api.DestroySemaphore(_resources.Device, ImageAvailableSemaphore, null);
_resources.Api.DestroySemaphore(_resources.Device, RenderFinishedSemaphore, null);
}
}
}
19 changes: 7 additions & 12 deletions samples/GpuInterop/VulkanDemo/VulkanSwapchain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public VulkanSwapchainImage(VulkanContext vk, PixelSize size, ICompositionGpuInt
_interop = interop;
_target = target;
Size = size;
_image = new VulkanImage(vk, (uint)Format.R8G8B8A8Unorm, size, true);
_image = new VulkanImage(vk, (uint)Format.R8G8B8A8Unorm, size, true, interop.SupportedImageHandleTypes);
_semaphorePair = new VulkanSemaphorePair(vk, true);
}

Expand Down Expand Up @@ -83,7 +83,7 @@ public void BeginDraw()
ImageLayout.Undefined, AccessFlags.None,
ImageLayout.ColorAttachmentOptimal, AccessFlags.ColorAttachmentReadBit);

if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
if(_image.IsDirectXBacked)
buffer.Submit(null,null,null, null, new VulkanCommandBufferPool.VulkanCommandBuffer.KeyedMutexSubmitInfo
{
AcquireKey = 0,
Expand Down Expand Up @@ -111,8 +111,7 @@ public void Present()
_image.TransitionLayout(buffer.InternalHandle, ImageLayout.TransferSrcOptimal, AccessFlags.TransferWriteBit);



if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
if (_image.IsDirectXBacked)
{
buffer.Submit(null, null, null, null,
new VulkanCommandBufferPool.VulkanCommandBuffer.KeyedMutexSubmitInfo
Expand All @@ -123,15 +122,11 @@ public void Present()
else
buffer.Submit(null, null, new[] { _semaphorePair.RenderFinishedSemaphore });

if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
if (!_image.IsDirectXBacked)
{
_availableSemaphore ??= _interop.ImportSemaphore(new PlatformHandle(
new IntPtr(_semaphorePair.ExportFd(false)),
KnownPlatformGraphicsExternalSemaphoreHandleTypes.VulkanOpaquePosixFileDescriptor));
_availableSemaphore ??= _interop.ImportSemaphore(_semaphorePair.Export(false));

_renderCompletedSemaphore ??= _interop.ImportSemaphore(new PlatformHandle(
new IntPtr(_semaphorePair.ExportFd(true)),
KnownPlatformGraphicsExternalSemaphoreHandleTypes.VulkanOpaquePosixFileDescriptor));
_renderCompletedSemaphore ??= _interop.ImportSemaphore(_semaphorePair.Export(true));
}

_importedImage ??= _interop.ImportImage(_image.Export(),
Expand All @@ -143,7 +138,7 @@ public void Present()
MemorySize = _image.MemorySize
});

if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
if (_image.IsDirectXBacked)
_lastPresent = _target.UpdateWithKeyedMutexAsync(_importedImage, 1, 0);
else
_lastPresent = _target.UpdateWithSemaphoresAsync(_importedImage, _renderCompletedSemaphore!, _availableSemaphore!);
Expand Down
1 change: 1 addition & 0 deletions src/Avalonia.Base/Avalonia.Base.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
<InternalsVisibleTo Include="Avalonia.Markup.Xaml, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Markup.Xaml.Loader, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.OpenGL, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Vulkan, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Skia, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Controls.ColorPicker, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Controls.DataGrid, PublicKey=$(AvaloniaPublicKey)" />
Expand Down
Loading
Loading