Browse Source

Use Silk.NET in GpuInterop sample (#20133)

* Replace SharpDX with Silk.NET in GpuInterop sample

* Add Vulkan/D3D11 command line switch to GpuInterop

* Fixed warnings in GpuInterop
pull/20170/head
Julien Lebosquain 2 months ago
committed by GitHub
parent
commit
4357a8dafc
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 4
      samples/GpuInterop/App.axaml.cs
  2. 187
      samples/GpuInterop/D3DDemo/D3D11DemoControl.cs
  3. 80
      samples/GpuInterop/D3DDemo/D3D11Swapchain.cs
  4. 224
      samples/GpuInterop/D3DDemo/D3DContent.cs
  5. 7
      samples/GpuInterop/DemoType.cs
  6. 14
      samples/GpuInterop/GpuInterop.csproj
  7. 10
      samples/GpuInterop/MainWindow.axaml
  8. 22
      samples/GpuInterop/MainWindow.axaml.cs
  9. 32
      samples/GpuInterop/Program.cs
  10. 12
      samples/GpuInterop/Properties/launchSettings.json
  11. 117
      samples/GpuInterop/VulkanDemo/D3DMemoryHelper.cs
  12. 4
      samples/GpuInterop/VulkanDemo/VulkanBufferHelper.cs
  13. 18
      samples/GpuInterop/VulkanDemo/VulkanCommandBufferPool.cs
  14. 43
      samples/GpuInterop/VulkanDemo/VulkanContent.cs
  15. 33
      samples/GpuInterop/VulkanDemo/VulkanContext.cs
  16. 49
      samples/GpuInterop/VulkanDemo/VulkanImage.cs
  17. 2
      samples/GpuInterop/VulkanDemo/VulkanMemoryHelper.cs
  18. 8
      samples/GpuInterop/VulkanDemo/VulkanSemaphorePair.cs
  19. 8
      samples/GpuInterop/VulkanDemo/VulkanSwapchain.cs
  20. 2
      samples/GpuInterop/VulkanDemo/VulkanTimelineSemaphore.cs

4
samples/GpuInterop/App.axaml.cs

@ -6,6 +6,8 @@ namespace GpuInterop
{
public class App : Application
{
public DemoType DemoType { get; set; }
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
@ -15,7 +17,7 @@ namespace GpuInterop
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktopLifetime)
{
desktopLifetime.MainWindow = new MainWindow();
desktopLifetime.MainWindow = new MainWindow(DemoType);
}
}
}

187
samples/GpuInterop/D3DDemo/D3D11DemoControl.cs

@ -5,57 +5,79 @@ using System.Numerics;
using Avalonia;
using Avalonia.Platform;
using Avalonia.Rendering.Composition;
using SharpDX;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using SharpDX.Mathematics.Interop;
using Buffer = SharpDX.Direct3D11.Buffer;
using DxgiFactory1 = SharpDX.DXGI.Factory1;
using Matrix = SharpDX.Matrix;
using D3DDevice = SharpDX.Direct3D11.Device;
using FeatureLevel = SharpDX.Direct3D.FeatureLevel;
using Vector3 = SharpDX.Vector3;
using Silk.NET.Core.Native;
using Silk.NET.Direct3D11;
using Silk.NET.DXGI;
using static Silk.NET.Core.Native.SilkMarshal;
namespace GpuInterop.D3DDemo;
public class D3D11DemoControl : DrawingSurfaceDemoBase
{
private D3DDevice? _device;
private ComPtr<ID3D11Device> _device;
private D3D11Swapchain? _swapchain;
private DeviceContext? _context;
private Matrix _view;
private ComPtr<ID3D11DeviceContext> _context;
private Matrix4x4 _view;
private PixelSize _lastSize;
private Texture2D? _depthBuffer;
private DepthStencilView? _depthView;
private Matrix _proj;
private Buffer? _constantBuffer;
private ComPtr<ID3D11Texture2D> _depthBuffer;
private ComPtr<ID3D11DepthStencilView> _depthView;
private Matrix4x4 _proj;
private ComPtr<ID3D11Buffer> _constantBuffer;
private readonly Stopwatch _st = Stopwatch.StartNew();
protected override (bool success, string info) InitializeGraphicsResources(Compositor compositor,
protected override unsafe (bool success, string info) InitializeGraphicsResources(Compositor compositor,
CompositionDrawingSurface surface, ICompositionGpuInterop interop)
{
if (interop.SupportedImageHandleTypes.Contains(KnownPlatformGraphicsExternalImageHandleTypes
.D3D11TextureGlobalSharedHandle) != true)
return (false, "DXGI shared handle import is not supported by the current graphics backend");
var factory = new DxgiFactory1();
using var adapter = factory.GetAdapter1(0);
_device = new D3DDevice(adapter, DeviceCreationFlags.None, new[]
using var dxgi = new DXGI(DXGI.CreateDefaultContext(["DXGI.dll"]));
using var d3d11 = new D3D11(D3D11.CreateDefaultContext(["d3d11.dll"]));
using var factory = dxgi.CreateDXGIFactory1<IDXGIFactory1>();
using ComPtr<IDXGIAdapter> adapter = default;
ThrowHResult(factory.EnumAdapters(0, adapter.GetAddressOf()));
const int featureLevelCount = 8;
var featureLevels = stackalloc D3DFeatureLevel[featureLevelCount]
{
FeatureLevel.Level_12_1,
FeatureLevel.Level_12_0,
FeatureLevel.Level_11_1,
FeatureLevel.Level_11_0,
FeatureLevel.Level_10_0,
FeatureLevel.Level_9_3,
FeatureLevel.Level_9_2,
FeatureLevel.Level_9_1,
});
_swapchain = new D3D11Swapchain(_device, interop, surface);
_context = _device.ImmediateContext;
D3DFeatureLevel.Level121,
D3DFeatureLevel.Level120,
D3DFeatureLevel.Level111,
D3DFeatureLevel.Level110,
D3DFeatureLevel.Level100,
D3DFeatureLevel.Level93,
D3DFeatureLevel.Level92,
D3DFeatureLevel.Level91
};
ComPtr<ID3D11Device> device = default;
ComPtr<ID3D11DeviceContext> context = default;
D3DFeatureLevel actualFeatureLevel;
ThrowHResult(d3d11.CreateDevice(
adapter,
D3DDriverType.Unknown,
IntPtr.Zero,
0u,
featureLevels,
featureLevelCount,
D3D11.SdkVersion,
device.GetAddressOf(),
&actualFeatureLevel,
context.GetAddressOf()));
_device = device;
_swapchain = new D3D11Swapchain(device, interop, surface);
_context = context;
_constantBuffer = D3DContent.CreateMesh(_device);
_view = Matrix.LookAtLH(new Vector3(0, 0, -5), new Vector3(0, 0, 0), Vector3.UnitY);
return (true, $"D3D11 ({_device.FeatureLevel}) {adapter.Description1.Description}");
_view = Matrix4x4.CreateLookAtLeftHanded(new Vector3(0, 0, -5), new Vector3(0, 0, 0), Vector3.UnitY);
AdapterDesc adapterDesc;
ThrowHResult(adapter.GetDesc(&adapterDesc));
var description = PtrToString((IntPtr)adapterDesc.Description, NativeStringEncoding.LPWStr);
return (true, $"D3D11 ({actualFeatureLevel}) {description}");
}
protected override void FreeGraphicsResources()
@ -66,16 +88,16 @@ public class D3D11DemoControl : DrawingSurfaceDemoBase
_swapchain = null;
}
Utilities.Dispose(ref _depthView);
Utilities.Dispose(ref _depthBuffer);
Utilities.Dispose(ref _constantBuffer);
Utilities.Dispose(ref _context);
Utilities.Dispose(ref _device);
_depthView.Dispose();
_depthBuffer.Dispose();
_constantBuffer.Dispose();
_context.Dispose();
_device.Dispose();
}
protected override bool SupportsDisco => true;
protected override void RenderFrame(PixelSize pixelSize)
protected override unsafe void RenderFrame(PixelSize pixelSize)
{
if (pixelSize == default)
return;
@ -86,69 +108,70 @@ public class D3D11DemoControl : DrawingSurfaceDemoBase
}
using (_swapchain!.BeginDraw(pixelSize, out var renderView))
{
_device!.ImmediateContext.OutputMerger.SetTargets(_depthView, renderView);
var viewProj = Matrix.Multiply(_view, _proj);
var context = _device.ImmediateContext;
var renderViewHandle = renderView.Handle;
_context.OMSetRenderTargets(1, &renderViewHandle, _depthView);
var viewProj = _view * _proj;
var now = _st.Elapsed.TotalSeconds * 5;
var scaleX = (float)(1f + Disco * (Math.Sin(now) + 1) / 6);
var scaleY = (float)(1f + Disco * (Math.Cos(now) + 1) / 8);
var colorOff =(float) (Math.Sin(now) + 1) / 2 * Disco;
// Clear views
context.ClearDepthStencilView(_depthView, DepthStencilClearFlags.Depth, 1.0f, 0);
context.ClearRenderTargetView(renderView,
new RawColor4(1 - colorOff, colorOff, (float)0.5 + colorOff / 2, 1));
_context.ClearDepthStencilView(_depthView, (uint)ClearFlag.Depth, 1.0f, 0);
var color = new Vector4(1f - colorOff, colorOff, 0.5f + colorOff * 0.5f, 1.0f);
_context.ClearRenderTargetView(renderView, (float*)&color);
var ypr = Matrix4x4.CreateFromYawPitchRoll(Yaw, Pitch, Roll);
// Update WorldViewProj Matrix
var worldViewProj = Matrix.RotationX(Yaw) * Matrix.RotationY(Pitch)
* Matrix.RotationZ(Roll)
* Matrix.Scaling(new Vector3(scaleX, scaleY, 1))
* viewProj;
worldViewProj.Transpose();
context.UpdateSubresource(ref worldViewProj, _constantBuffer);
var ypr = Matrix4x4.CreateFromYawPitchRoll(Yaw, Pitch, Roll);
var worldViewProj = ypr * Matrix4x4.CreateScale(new Vector3(scaleX, scaleY, 1)) * viewProj;
worldViewProj = Matrix4x4.Transpose(worldViewProj);
_context.UpdateSubresource(_constantBuffer, 0, null, &worldViewProj, 0, 0);
// Draw the cube
context.Draw(36, 0);
_context.Draw(36, 0);
_context!.Flush();
_context.Flush();
}
}
private void Resize(PixelSize size)
private unsafe void Resize(PixelSize size)
{
Utilities.Dispose(ref _depthBuffer);
_depthBuffer.Dispose();
if (_device is null)
if (_device.Handle == null)
return;
_depthBuffer = new Texture2D(_device,
new Texture2DDescription()
{
Format = Format.D32_Float_S8X24_UInt,
ArraySize = 1,
MipLevels = 1,
Width = size.Width,
Height = size.Height,
SampleDescription = new SampleDescription(1, 0),
Usage = ResourceUsage.Default,
BindFlags = BindFlags.DepthStencil,
CpuAccessFlags = CpuAccessFlags.None,
OptionFlags = ResourceOptionFlags.None
});
Utilities.Dispose(ref _depthView);
_depthView = new DepthStencilView(_device, _depthBuffer);
ComPtr<ID3D11Texture2D> depthBuffer = default;
var textureDesc = new Texture2DDesc
{
Format = Format.FormatD32FloatS8X24Uint,
ArraySize = 1,
MipLevels = 1,
Width = (uint)size.Width,
Height = (uint)size.Height,
SampleDesc = new SampleDesc(1, 0),
Usage = Usage.Default,
BindFlags = (uint)BindFlag.DepthStencil,
CPUAccessFlags = (uint)CpuAccessFlag.None,
MiscFlags = (uint)ResourceMiscFlag.None
};
ThrowHResult(_device.CreateTexture2D(
&textureDesc,
(SubresourceData*)null,
depthBuffer.GetAddressOf()));
_depthBuffer = depthBuffer;
_depthView.Dispose();
ThrowHResult(_device.CreateDepthStencilView(_depthBuffer, null, ref _depthView));
// Setup targets and viewport for rendering
_device.ImmediateContext.Rasterizer.SetViewport(new Viewport(0, 0, size.Width, size.Height, 0.0f, 1.0f));
var viewport = new Viewport(0, 0, size.Width, size.Height, 0.0f, 1.0f);
_context.RSSetViewports(1, &viewport);
// Setup new projection matrix with correct aspect ratio
_proj = Matrix.PerspectiveFovLH((float)Math.PI / 4.0f, size.Width / (float) size.Height, 0.1f, 100.0f);
_proj = Matrix4x4.CreatePerspectiveFieldOfViewLeftHanded((float)Math.PI / 4.0f, size.Width / (float) size.Height, 0.1f, 100.0f);
}
}

80
samples/GpuInterop/D3DDemo/D3D11Swapchain.cs

@ -1,22 +1,22 @@
using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Rendering.Composition;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using DxgiFactory1 = SharpDX.DXGI.Factory1;
using D3DDevice = SharpDX.Direct3D11.Device;
using DxgiResource = SharpDX.DXGI.Resource;
using Silk.NET.Core.Native;
using Silk.NET.Direct3D11;
using Silk.NET.DXGI;
using static Silk.NET.Core.Native.SilkMarshal;
namespace GpuInterop.D3DDemo;
class D3D11Swapchain : SwapchainBase<D3D11SwapchainImage>
{
private readonly D3DDevice _device;
private readonly ComPtr<ID3D11Device> _device;
public D3D11Swapchain(D3DDevice device, ICompositionGpuInterop interop, CompositionDrawingSurface target)
public D3D11Swapchain(ComPtr<ID3D11Device> device, ICompositionGpuInterop interop, CompositionDrawingSurface target)
: base(interop, target)
{
_device = device;
@ -24,7 +24,7 @@ class D3D11Swapchain : SwapchainBase<D3D11SwapchainImage>
protected override D3D11SwapchainImage CreateImage(PixelSize size) => new(_device, size, Interop, Target);
public IDisposable BeginDraw(PixelSize size, out RenderTargetView view)
public IDisposable BeginDraw(PixelSize size, out ComPtr<ID3D11RenderTargetView> view)
{
var rv = BeginDrawCore(size, out var image);
view = image.RenderTargetView;
@ -37,53 +37,67 @@ public class D3D11SwapchainImage : ISwapchainImage
public PixelSize Size { get; }
private readonly ICompositionGpuInterop _interop;
private readonly CompositionDrawingSurface _target;
private readonly Texture2D _texture;
private readonly KeyedMutex _mutex;
private ComPtr<ID3D11Texture2D> _texture;
private ComPtr<IDXGIKeyedMutex> _mutex;
private ComPtr<ID3D11RenderTargetView> _renderTargetView;
private readonly IntPtr _handle;
private PlatformGraphicsExternalImageProperties _properties;
private ICompositionImportedGpuImage? _imported;
public Task? LastPresent { get; private set; }
public RenderTargetView RenderTargetView { get; }
public ComPtr<ID3D11RenderTargetView> RenderTargetView => _renderTargetView;
public D3D11SwapchainImage(D3DDevice device, PixelSize size,
public unsafe D3D11SwapchainImage(
ComPtr<ID3D11Device> device,
PixelSize size,
ICompositionGpuInterop interop,
CompositionDrawingSurface target)
{
Size = size;
_interop = interop;
_target = target;
_texture = new Texture2D(device,
new Texture2DDescription
{
Format = Format.R8G8B8A8_UNorm,
Width = size.Width,
Height = size.Height,
ArraySize = 1,
MipLevels = 1,
SampleDescription = new SampleDescription { Count = 1, Quality = 0 },
CpuAccessFlags = default,
OptionFlags = ResourceOptionFlags.SharedKeyedmutex,
BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource
});
_mutex = _texture.QueryInterface<KeyedMutex>();
using (var res = _texture.QueryInterface<DxgiResource>())
_handle = res.SharedHandle;
ComPtr<ID3D11Texture2D> texture = default;
var textureDesc = new Texture2DDesc
{
Format = Format.FormatR8G8B8A8Unorm,
Width = (uint)size.Width,
Height = (uint)size.Height,
ArraySize = 1,
MipLevels = 1,
SampleDesc = new SampleDesc(1, 0),
Usage = Usage.Default,
BindFlags = (uint)(BindFlag.RenderTarget | BindFlag.ShaderResource),
CPUAccessFlags = 0,
MiscFlags = (uint)ResourceMiscFlag.SharedKeyedmutex
};
ThrowHResult(device.CreateTexture2D(&textureDesc, (SubresourceData*)null, texture.GetAddressOf()));
_texture = texture;
_mutex = _texture.QueryInterface<IDXGIKeyedMutex>();
using (var res = _texture.QueryInterface<IDXGIResource>())
{
void* handle = null;
ThrowHResult(res.GetSharedHandle(ref handle));
_handle = (IntPtr)handle;
}
_properties = new PlatformGraphicsExternalImageProperties
{
Width = size.Width, Height = size.Height, Format = PlatformGraphicsExternalImageFormat.B8G8R8A8UNorm
};
RenderTargetView = new RenderTargetView(device, _texture);
ThrowHResult(device.CreateRenderTargetView(_texture, null, ref _renderTargetView));
}
public void BeginDraw()
{
_mutex.Acquire(0, int.MaxValue);
_mutex.AcquireSync(0, int.MaxValue);
}
public void Present()
{
_mutex.Release(1);
_mutex.ReleaseSync(1);
_imported ??= _interop.ImportImage(
new PlatformHandle(_handle, KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureGlobalSharedHandle),
_properties);
@ -103,8 +117,8 @@ public class D3D11SwapchainImage : ISwapchainImage
// Ignore
}
RenderTargetView.Dispose();
_renderTargetView.Dispose();
_mutex.Dispose();
_texture.Dispose();
}
}
}

224
samples/GpuInterop/D3DDemo/D3DContent.cs

@ -1,110 +1,158 @@
using SharpDX;
using SharpDX.D3DCompiler;
using SharpDX.Direct3D;
using System;
using System.Linq;
using System.Threading.Tasks;
using SharpDX.Direct2D1;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using SharpDX.Mathematics.Interop;
using Buffer = SharpDX.Direct3D11.Buffer;
using DeviceContext = SharpDX.Direct2D1.DeviceContext;
using DxgiFactory1 = SharpDX.DXGI.Factory1;
using Matrix = SharpDX.Matrix;
using D3DDevice = SharpDX.Direct3D11.Device;
using DxgiResource = SharpDX.DXGI.Resource;
using FeatureLevel = SharpDX.Direct3D.FeatureLevel;
using InputElement = SharpDX.Direct3D11.InputElement;
using System.Numerics;
using Silk.NET.Core.Native;
using Silk.NET.Direct3D.Compilers;
using Silk.NET.Direct3D11;
using Silk.NET.DXGI;
using static Silk.NET.Core.Native.SilkMarshal;
namespace GpuInterop.D3DDemo;
public class D3DContent
public static class D3DContent
{
private static D3DCompiler s_compiler = D3DCompiler.GetApi();
public static Buffer CreateMesh(D3DDevice device)
public static unsafe ComPtr<ID3D11Buffer> CreateMesh(ComPtr<ID3D11Device> device)
{
// Compile Vertex and Pixel shaders
var vertexShaderByteCode = ShaderBytecode.CompileFromFile("D3DDemo\\MiniCube.fx", "VS", "vs_4_0");
var vertexShader = new VertexShader(device, vertexShaderByteCode);
using var vertexShaderByteCode = CompileShader("D3DDemo\\MiniCube.fx", "VS", "vs_4_0");
using ComPtr<ID3D11VertexShader> vertexShader = default;
ThrowHResult(device.CreateVertexShader(
vertexShaderByteCode.GetBufferPointer(),
vertexShaderByteCode.GetBufferSize(),
(ID3D11ClassLinkage*)null,
vertexShader.GetAddressOf()));
var pixelShaderByteCode = ShaderBytecode.CompileFromFile("D3DDemo\\MiniCube.fx", "PS", "ps_4_0");
var pixelShader = new PixelShader(device, pixelShaderByteCode);
using var pixelShaderByteCode = CompileShader("D3DDemo\\MiniCube.fx", "PS", "ps_4_0");
using ComPtr<ID3D11PixelShader> pixelShader = default;
ThrowHResult(device.CreatePixelShader(
pixelShaderByteCode.GetBufferPointer(),
pixelShaderByteCode.GetBufferSize(),
(ID3D11ClassLinkage*)null,
pixelShader.GetAddressOf()));
var signature = ShaderSignature.GetInputSignature(vertexShaderByteCode);
using ComPtr<ID3D10Blob> vertexShaderSignature = default;
ThrowHResult(s_compiler.GetInputSignatureBlob(
vertexShaderByteCode.GetBufferPointer(),
vertexShaderByteCode.GetBufferSize(),
vertexShaderSignature.GetAddressOf()));
var inputElements = new[]
// Layout from VertexShader input signature
using ComPtr<ID3D11InputLayout> inputLayout = default;
var positionNamePtr = StringToPtr("POSITION", NativeStringEncoding.LPStr);
var colorNamePtr = StringToPtr("COLOR", NativeStringEncoding.LPStr);
try
{
new InputElement("POSITION", 0, Format.R32G32B32A32_Float, 0, 0),
new InputElement("COLOR", 0, Format.R32G32B32A32_Float, 16, 0)
};
const int inputCount = 2;
var inputs = stackalloc InputElementDesc[inputCount]
{
new InputElementDesc((byte*)positionNamePtr, 0, Format.FormatR32G32B32A32Float, 0, 0),
new InputElementDesc((byte*)colorNamePtr, 0, Format.FormatR32G32B32A32Float, 0, 16)
};
// Layout from VertexShader input signature
var layout = new InputLayout(
device,
signature,
inputElements);
ThrowHResult(device.CreateInputLayout(
inputs,
inputCount,
vertexShaderSignature.GetBufferPointer(),
vertexShaderSignature.GetBufferSize(),
inputLayout.GetAddressOf()));
}
finally
{
FreeString(positionNamePtr, NativeStringEncoding.LPStr);
FreeString(colorNamePtr, NativeStringEncoding.LPStr);
}
// Instantiate Vertex buffer from vertex data
using var vertices = Buffer.Create(
device,
BindFlags.VertexBuffer,
new[]
var vertices = new[]
{
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f), // Front
new Vector4(-1.0f, 1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
new Vector4(1.0f, 1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
new Vector4(1.0f, 1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
new Vector4(1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f), // BACK
new Vector4(1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
new Vector4(1.0f, -1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
new Vector4(1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, 1.0f, -1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f), // Top
new Vector4(-1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
new Vector4(1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, 1.0f, -1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
new Vector4(1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
new Vector4(1.0f, 1.0f, -1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f), // Bottom
new Vector4(1.0f, -1.0f, 1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, 1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
new Vector4(1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
new Vector4(1.0f, -1.0f, 1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f), // Left
new Vector4(-1.0f, -1.0f, 1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, 1.0f, 1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, 1.0f, 1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, 1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
new Vector4(1.0f, -1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f), // Right
new Vector4(1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
new Vector4(1.0f, -1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
new Vector4(1.0f, -1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
new Vector4(1.0f, 1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
new Vector4(1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
};
using ComPtr<ID3D11Buffer> vertexBuffer = default;
fixed (Vector4* verticesPtr = vertices)
{
var vertexBufferDesc = new BufferDesc
{
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f), // Front
new Vector4(-1.0f, 1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
new Vector4(1.0f, 1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
new Vector4(1.0f, 1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
new Vector4(1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f), // BACK
new Vector4(1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
new Vector4(1.0f, -1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
new Vector4(1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, 1.0f, -1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f), // Top
new Vector4(-1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
new Vector4(1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, 1.0f, -1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
new Vector4(1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
new Vector4(1.0f, 1.0f, -1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f), // Bottom
new Vector4(1.0f, -1.0f, 1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, 1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
new Vector4(1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
new Vector4(1.0f, -1.0f, 1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f), // Left
new Vector4(-1.0f, -1.0f, 1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, 1.0f, 1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, 1.0f, 1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, 1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
new Vector4(1.0f, -1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f), // Right
new Vector4(1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
new Vector4(1.0f, -1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
new Vector4(1.0f, -1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
new Vector4(1.0f, 1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
new Vector4(1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
});
ByteWidth = (uint)(sizeof(Vector4) * vertices.Length),
Usage = Usage.Default,
BindFlags = (uint)BindFlag.VertexBuffer,
CPUAccessFlags = (uint)CpuAccessFlag.None,
MiscFlags = (uint)ResourceMiscFlag.None,
StructureByteStride = 0
};
var subresourceData = new SubresourceData(verticesPtr);
ThrowHResult(device.CreateBuffer(&vertexBufferDesc, &subresourceData, vertexBuffer.GetAddressOf()));
}
// Create Constant Buffer
var constantBuffer = new Buffer(device, Utilities.SizeOf<Matrix>(), ResourceUsage.Default,
BindFlags.ConstantBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);
var context = device.ImmediateContext;
ComPtr<ID3D11Buffer> constantBuffer = default;
var constantBufferDesc = new BufferDesc
{
ByteWidth = (uint)sizeof(Matrix4x4),
Usage = Usage.Default,
BindFlags = (uint)BindFlag.ConstantBuffer,
CPUAccessFlags = (uint)CpuAccessFlag.None,
MiscFlags = (uint)ResourceMiscFlag.None,
StructureByteStride = 0
};
ThrowHResult(device.CreateBuffer(&constantBufferDesc, (SubresourceData*)null, constantBuffer.GetAddressOf()));
// Prepare All the stages
context.InputAssembler.InputLayout = layout;
context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
context.InputAssembler.SetVertexBuffers(0,
new VertexBufferBinding(vertices, Utilities.SizeOf<Vector4>() * 2, 0));
context.VertexShader.SetConstantBuffer(0, constantBuffer);
context.VertexShader.Set(vertexShader);
context.PixelShader.Set(pixelShader);
using ComPtr<ID3D11DeviceContext> context = default;
device.GetImmediateContext(context.GetAddressOf());
context.IASetInputLayout(inputLayout);
context.IASetPrimitiveTopology(D3DPrimitiveTopology.D3D10PrimitiveTopologyTrianglelist);
var stride = (uint)(sizeof(Vector4) * 2);
var offset = 0u;
context.IASetVertexBuffers(0, 1, &vertexBuffer.Handle, &stride, &offset);
context.VSSetConstantBuffers(0, 1, &constantBuffer.Handle);
context.VSSetShader(vertexShader, (ID3D11ClassInstance**)null, 0);
context.PSSetShader(pixelShader, (ID3D11ClassInstance**)null, 0);
return constantBuffer;
}
private static unsafe ComPtr<ID3D10Blob> CompileShader(string fileName, string entryPoint, string profile)
{
ComPtr<ID3D10Blob> blob = default;
ThrowHResult(s_compiler.CompileFromFile(fileName, null, null, entryPoint, profile, 0u, 0u, blob.GetAddressOf(), null));
return blob;
}
}

7
samples/GpuInterop/DemoType.cs

@ -0,0 +1,7 @@
namespace GpuInterop;
public enum DemoType
{
Vulkan,
D3D11
}

14
samples/GpuInterop/GpuInterop.csproj

@ -7,7 +7,6 @@
<Nullable>enable</Nullable>
<GenerateDocumentationFile>false</GenerateDocumentationFile>
<UseD3DCompiler>true</UseD3DCompiler>
<UseSharpDXMathematics>true</UseSharpDXMathematics>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
@ -25,10 +24,13 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Silk.NET.Vulkan" Version="2.16.0" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.16.0" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.16.0" />
<PackageReference Include="System.Reactive" Version="5.0.0" />
<PackageReference Include="Silk.NET.Direct3D11" Version="2.22.0" />
<PackageReference Include="Silk.NET.Direct3D.Compilers" Version="2.22.0" />
<PackageReference Include="Silk.NET.Vulkan" Version="2.22.0" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.22.0" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.22.0" />
<!-- Silk.NET 2.22 targets an obsolete System.Text.Json, update to avoid warnings. -->
<PackageReference Include="System.Text.Json" Version="10.0.0" />
</ItemGroup>
<ItemGroup>
@ -37,6 +39,7 @@
<ItemGroup>
<Compile Include="..\..\src\Avalonia.Base\Rendering\SwapchainBase.cs" />
<Compile Include="..\..\src\Avalonia.Base\Reactive\Disposable.cs" />
<None Remove="VulkanDemo\Assets\Shaders\frag.spirv" />
<EmbeddedResource Include="VulkanDemo\Assets\Shaders\frag.spirv" />
<None Remove="VulkanDemo\Assets\Shaders\vert.spirv" />
@ -47,5 +50,4 @@
<Import Project="..\..\build\SampleApp.props" />
<Import Project="..\..\build\ReferenceCoreLibraries.props" />
<Import Project="..\..\build\BuildTargets.targets" />
<Import Project="..\..\build\SharpDX.props" />
</Project>

10
samples/GpuInterop/MainWindow.axaml

@ -1,13 +1,5 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
xmlns:gpuInterop="clr-namespace:GpuInterop"
xmlns:d3DDemo="clr-namespace:GpuInterop.D3DDemo"
xmlns:vulkanDemo="clr-namespace:GpuInterop.VulkanDemo"
x:Class="GpuInterop.MainWindow">
<gpuInterop:GpuDemo>
<gpuInterop:GpuDemo.Demo>
<!--<d3DDemo:D3D11DemoControl/>-->
<vulkanDemo:VulkanDemoControl/>
</gpuInterop:GpuDemo.Demo>
</gpuInterop:GpuDemo>
</Window>

22
samples/GpuInterop/MainWindow.axaml.cs

@ -1,15 +1,35 @@
using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.Rendering;
using GpuInterop.D3DDemo;
using GpuInterop.VulkanDemo;
namespace GpuInterop
{
public class MainWindow : Window
{
public MainWindow()
public MainWindow() : this(DemoType.Vulkan)
{
}
public MainWindow(DemoType demoType)
{
InitializeComponent();
Title = demoType.ToString();
Content = new GpuDemo
{
Demo = demoType switch
{
DemoType.Vulkan => new VulkanDemoControl(),
DemoType.D3D11 => new D3D11DemoControl(),
var unknown => throw new InvalidOperationException($"Unknown demo type {unknown}")
}
};
this.AttachDevTools();
RendererDiagnostics.DebugOverlays = RendererDebugOverlays.Fps;
}

32
samples/GpuInterop/Program.cs

@ -1,29 +1,35 @@
global using System.Reactive.Disposables;
using System;
using Avalonia;
using Avalonia.Logging;
using Avalonia.Vulkan;
namespace GpuInterop
{
public class Program
public static class Program
{
static void Main(string[] args) => BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
public static void Main(string[] args)
{
var demoType = OperatingSystem.IsWindows() && args.AsSpan().Contains("--d3d") ? DemoType.D3D11 : DemoType.Vulkan;
BuildAvaloniaAppCore(demoType).StartWithClassicDesktopLifetime(args);
}
public static AppBuilder BuildAvaloniaApp() =>
AppBuilder.Configure<App>()
public static AppBuilder BuildAvaloniaApp() => BuildAvaloniaAppCore(DemoType.Vulkan);
private static AppBuilder BuildAvaloniaAppCore(DemoType demoType) =>
AppBuilder
.Configure(() => new App { DemoType = demoType })
.UsePlatformDetect()
.With(new Win32PlatformOptions
{
RenderingMode = new []
{
Win32RenderingMode.Vulkan
}
RenderingMode = [demoType == DemoType.D3D11 ? Win32RenderingMode.AngleEgl : Win32RenderingMode.Vulkan]
})
.With(new X11PlatformOptions
{
RenderingMode = [X11RenderingMode.Vulkan]
})
.With(new X11PlatformOptions(){RenderingMode =new[] { X11RenderingMode.Vulkan } })
.With(new VulkanOptions()
.With(new VulkanOptions
{
VulkanInstanceCreationOptions = new VulkanInstanceCreationOptions()
VulkanInstanceCreationOptions = new VulkanInstanceCreationOptions
{
UseDebug = true
}

12
samples/GpuInterop/Properties/launchSettings.json

@ -0,0 +1,12 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": {
"GpuInterop (Vulkan)": {
"commandName": "Project",
},
"GpuInterop (Direct3D)": {
"commandName": "Project",
"commandLineArgs": "--d3d"
}
}
}

117
samples/GpuInterop/VulkanDemo/D3DMemoryHelper.cs

@ -1,54 +1,97 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Avalonia;
using SharpDX.Direct3D;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using D3DDevice = SharpDX.Direct3D11.Device;
using DxgiFactory1 = SharpDX.DXGI.Factory1;
using Silk.NET.Core.Native;
using Silk.NET.Direct3D11;
using Silk.NET.DXGI;
using VulkanFormat = Silk.NET.Vulkan.Format;
using static Silk.NET.Core.Native.SilkMarshal;
namespace GpuInterop.VulkanDemo;
public class D3DMemoryHelper
{
public static D3DDevice CreateDeviceByLuid(Span<byte> luid)
private const int DxgiErrorNotFound = unchecked((int)0x887A0002);
public static unsafe ComPtr<ID3D11Device> CreateDeviceByLuid(Luid luid)
{
var factory = new DxgiFactory1();
var longLuid = MemoryMarshal.Cast<byte, long>(luid)[0];
for (var c = 0; c < factory.GetAdapterCount1(); c++)
using var dxgi = new DXGI(DXGI.CreateDefaultContext(["DXGI.dll"]));
using var d3d11 = new D3D11(D3D11.CreateDefaultContext(["d3d11.dll"]));
using var factory = dxgi.CreateDXGIFactory1<IDXGIFactory1>();
using var adapter = GetAdapterByLuid(factory, luid);
const int featureLevelCount = 8;
var featureLevels = stackalloc D3DFeatureLevel[featureLevelCount]
{
using var adapter = factory.GetAdapter1(c);
if (adapter.Description1.Luid != longLuid)
continue;
return new D3DDevice(adapter, DeviceCreationFlags.None,
new[]
{
FeatureLevel.Level_12_1, FeatureLevel.Level_12_0, FeatureLevel.Level_11_1,
FeatureLevel.Level_11_0, FeatureLevel.Level_10_0, FeatureLevel.Level_9_3,
FeatureLevel.Level_9_2, FeatureLevel.Level_9_1,
});
D3DFeatureLevel.Level121,
D3DFeatureLevel.Level120,
D3DFeatureLevel.Level111,
D3DFeatureLevel.Level110,
D3DFeatureLevel.Level100,
D3DFeatureLevel.Level93,
D3DFeatureLevel.Level92,
D3DFeatureLevel.Level91
};
ComPtr<ID3D11Device> device = default;
ComPtr<ID3D11DeviceContext> context = default;
D3DFeatureLevel actualFeatureLevel;
ThrowHResult(d3d11.CreateDevice(
adapter,
D3DDriverType.Unknown,
IntPtr.Zero,
0u,
featureLevels,
featureLevelCount,
D3D11.SdkVersion,
device.GetAddressOf(),
&actualFeatureLevel,
context.GetAddressOf()));
return device;
}
private static unsafe ComPtr<IDXGIAdapter> GetAdapterByLuid(ComPtr<IDXGIFactory1> factory, Luid luid)
{
var index = 0u;
ComPtr<IDXGIAdapter> adapter = default;
while (factory.EnumAdapters(index, adapter.GetAddressOf()) != DxgiErrorNotFound)
{
AdapterDesc adapterDesc;
if (adapter.GetDesc(&adapterDesc) == 0 & AreLuidsEqual(adapterDesc.AdapterLuid, luid))
return adapter;
adapter.Dispose();
++index;
}
throw new ArgumentException("Device with the corresponding LUID not found");
}
public static Texture2D CreateMemoryHandle(D3DDevice device, PixelSize size, Silk.NET.Vulkan.Format format)
public static unsafe ComPtr<ID3D11Texture2D> CreateMemoryHandle(ComPtr<ID3D11Device> device, PixelSize size, VulkanFormat format)
{
if (format != Silk.NET.Vulkan.Format.R8G8B8A8Unorm)
if (format != VulkanFormat.R8G8B8A8Unorm)
throw new ArgumentException("Not supported format");
return new Texture2D(device,
new Texture2DDescription
{
Format = Format.R8G8B8A8_UNorm,
Width = size.Width,
Height = size.Height,
ArraySize = 1,
MipLevels = 1,
SampleDescription = new SampleDescription { Count = 1, Quality = 0 },
CpuAccessFlags = default,
OptionFlags = ResourceOptionFlags.SharedKeyedmutex|ResourceOptionFlags.SharedNthandle,
BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource
});
ComPtr<ID3D11Texture2D> texture = default;
var textureDesc = new Texture2DDesc
{
Format = Format.FormatR8G8B8A8Unorm,
Width = (uint)size.Width,
Height = (uint)size.Height,
ArraySize = 1,
MipLevels = 1,
SampleDesc = new SampleDesc(1, 0),
Usage = Usage.Default,
BindFlags = (uint)(BindFlag.RenderTarget | BindFlag.ShaderResource),
CPUAccessFlags = 0,
MiscFlags = (uint)(ResourceMiscFlag.SharedKeyedmutex | ResourceMiscFlag.SharedNthandle)
};
ThrowHResult(device.CreateTexture2D(&textureDesc, (SubresourceData*)null, texture.GetAddressOf()));
return texture;
}
private static bool AreLuidsEqual(Luid x, Luid y)
=> x.Low == y.Low && x.High == y.High;
}

4
samples/GpuInterop/VulkanDemo/VulkanBufferHelper.cs

@ -25,7 +25,7 @@ static class VulkanBufferHelper
Usage = bufferUsageFlags,
SharingMode = SharingMode.Exclusive
};
api.CreateBuffer(device, bufferInfo, null, out buffer).ThrowOnError();
api.CreateBuffer(device, in bufferInfo, null, out buffer).ThrowOnError();
api.GetBufferMemoryRequirements(device, buffer, out var memoryRequirements);
@ -42,7 +42,7 @@ static class VulkanBufferHelper
MemoryPropertyFlags.HostVisibleBit)
};
api.AllocateMemory(device, memoryAllocateInfo, null, out memory).ThrowOnError();
api.AllocateMemory(device, in memoryAllocateInfo, null, out memory).ThrowOnError();
api.BindBufferMemory(device, buffer, memory, 0);
UpdateBufferMemory(vk, memory, initialData);
}

18
samples/GpuInterop/VulkanDemo/VulkanCommandBufferPool.cs

@ -28,7 +28,7 @@ namespace Avalonia.Vulkan
QueueFamilyIndex = queueFamilyIndex
};
_api.CreateCommandPool(_device, commandPoolCreateInfo, null, out _commandPool)
_api.CreateCommandPool(_device, in commandPoolCreateInfo, null, out _commandPool)
.ThrowOnError();
}
@ -53,7 +53,7 @@ namespace Avalonia.Vulkan
lock (_lock)
{
_api.AllocateCommandBuffers(_device, commandBufferAllocateInfo, out var commandBuffer);
_api.AllocateCommandBuffers(_device, in commandBufferAllocateInfo, out var commandBuffer);
return commandBuffer;
}
@ -111,15 +111,16 @@ namespace Avalonia.Vulkan
Flags = FenceCreateFlags.SignaledBit
};
api.CreateFence(device, fenceCreateInfo, null, out _fence);
api.CreateFence(device, in fenceCreateInfo, null, out _fence);
}
public unsafe void Dispose()
{
_api.WaitForFences(_device, 1, _fence, true, ulong.MaxValue);
_api.WaitForFences(_device, 1, in _fence, true, ulong.MaxValue);
lock (_commandBufferPool._lock)
{
_api.FreeCommandBuffers(_device, _commandBufferPool._commandPool, 1, InternalHandle);
var handle = InternalHandle;
_api.FreeCommandBuffers(_device, _commandBufferPool._commandPool, 1, in handle);
}
_api.DestroyFence(_device, _fence, null);
}
@ -136,7 +137,7 @@ namespace Avalonia.Vulkan
Flags = CommandBufferUsageFlags.OneTimeSubmitBit
};
_api.BeginCommandBuffer(InternalHandle, beginInfo);
_api.BeginCommandBuffer(InternalHandle, in beginInfo);
}
}
@ -212,9 +213,10 @@ namespace Avalonia.Vulkan
PSignalSemaphores = pSignalSemaphores,
};
_api.ResetFences(_device, 1, fence.Value);
var fenceValue = fence.Value;
_api.ResetFences(_device, 1, in fenceValue);
_api.QueueSubmit(_queue, 1, submitInfo, fence.Value);
_api.QueueSubmit(_queue, 1, in submitInfo, fenceValue);
}
}

43
samples/GpuInterop/VulkanDemo/VulkanContent.cs

@ -93,7 +93,7 @@ unsafe class VulkanContent : IDisposable
PCode = (uint*)ptr,
};
api.CreateShaderModule(device, shaderCreateInfo, null, out _vertShader);
api.CreateShaderModule(device, in shaderCreateInfo, null, out _vertShader);
}
fixed (byte* ptr = fragShaderData)
@ -105,7 +105,7 @@ unsafe class VulkanContent : IDisposable
PCode = (uint*)ptr,
};
api.CreateShaderModule(device, shaderCreateInfo, null, out _fragShader);
api.CreateShaderModule(device, in shaderCreateInfo, null, out _fragShader);
}
CreateBuffers();
@ -160,16 +160,16 @@ unsafe class VulkanContent : IDisposable
var commandBufferHandle = new CommandBuffer(commandBuffer.Handle);
api.CmdSetViewport(commandBufferHandle, 0, 1,
new Viewport()
{
Width = (float)image.Size.Width,
Height = (float)image.Size.Height,
MaxDepth = 1,
MinDepth = 0,
X = 0,
Y = 0
});
var viewport = new Viewport()
{
Width = (float)image.Size.Width,
Height = (float)image.Size.Height,
MaxDepth = 1,
MinDepth = 0,
X = 0,
Y = 0
};
api.CmdSetViewport(commandBufferHandle, 0, 1, in viewport);
var scissor = new Rect2D
{
@ -196,7 +196,7 @@ unsafe class VulkanContent : IDisposable
PClearValues = clearValue
};
api.CmdBeginRenderPass(commandBufferHandle, beginInfo, SubpassContents.Inline);
api.CmdBeginRenderPass(commandBufferHandle, in beginInfo, SubpassContents.Inline);
}
api.CmdBindPipeline(commandBufferHandle, PipelineBindPoint.Graphics, _pipeline);
@ -207,7 +207,8 @@ unsafe class VulkanContent : IDisposable
api.CmdPushConstants(commandBufferHandle, _pipelineLayout, ShaderStageFlags.VertexBit | ShaderStageFlags.FragmentBit, 0,
(uint)Marshal.SizeOf<VertexPushConstant>(), &vertexConstant);
api.CmdBindVertexBuffers(commandBufferHandle, 0, 1, _vertexBuffer, 0);
var offsets = 0ul;
api.CmdBindVertexBuffers(commandBufferHandle, 0, 1, in _vertexBuffer, in offsets);
api.CmdBindIndexBuffer(commandBufferHandle, _indexBuffer, 0, IndexType.Uint16);
api.CmdDrawIndexed(commandBufferHandle, (uint)_indices.Length, 1, 0, 0, 0);
@ -250,7 +251,7 @@ unsafe class VulkanContent : IDisposable
api.CmdBlitImage(commandBuffer.InternalHandle, _colorAttachment.InternalHandle,
ImageLayout.TransferSrcOptimal,
image.InternalHandle, ImageLayout.TransferDstOptimal, 1, srcBlitRegion, Filter.Linear);
image.InternalHandle, ImageLayout.TransferDstOptimal, 1, in srcBlitRegion, Filter.Linear);
commandBuffer.Submit();
}
@ -341,7 +342,7 @@ unsafe class VulkanContent : IDisposable
var api = _context.Api;
var device = _context.Device;
api
.CreateImage(device, imageCreateInfo, null, out _depthImage).ThrowOnError();
.CreateImage(device, in imageCreateInfo, null, out _depthImage).ThrowOnError();
api.GetImageMemoryRequirements(device, _depthImage,
out var memoryRequirements);
@ -355,7 +356,7 @@ unsafe class VulkanContent : IDisposable
memoryRequirements.MemoryTypeBits, MemoryPropertyFlags.DeviceLocalBit)
};
api.AllocateMemory(device, memoryAllocateInfo, null,
api.AllocateMemory(device, in memoryAllocateInfo, null,
out _depthImageMemory).ThrowOnError();
api.BindImageMemory(device, _depthImage, _depthImageMemory, 0);
@ -380,7 +381,7 @@ unsafe class VulkanContent : IDisposable
};
api
.CreateImageView(device, imageViewCreateInfo, null, out _depthImageView)
.CreateImageView(device, in imageViewCreateInfo, null, out _depthImageView)
.ThrowOnError();
}
@ -467,7 +468,7 @@ unsafe class VulkanContent : IDisposable
PDependencies = &subpassDependency
};
api.CreateRenderPass(device, renderPassCreateInfo, null, out _renderPass).ThrowOnError();
api.CreateRenderPass(device, in renderPassCreateInfo, null, out _renderPass).ThrowOnError();
// create framebuffer
@ -486,7 +487,7 @@ unsafe class VulkanContent : IDisposable
Layers = 1
};
api.CreateFramebuffer(device, framebufferCreateInfo, null, out _framebuffer).ThrowOnError();
api.CreateFramebuffer(device, in framebufferCreateInfo, null, out _framebuffer).ThrowOnError();
}
}
@ -691,7 +692,7 @@ unsafe class VulkanContent : IDisposable
PSetLayouts = &setLayout
};
api.CreatePipelineLayout(device, pipelineLayoutCreateInfo, null, out _pipelineLayout)
api.CreatePipelineLayout(device, in pipelineLayoutCreateInfo, null, out _pipelineLayout)
.ThrowOnError();
}

33
samples/GpuInterop/VulkanDemo/VulkanContext.cs

@ -9,13 +9,15 @@ using Avalonia.Vulkan;
using Silk.NET.Core;
using Silk.NET.Core.Contexts;
using Silk.NET.Core.Loader;
using Silk.NET.Core.Native;
using Silk.NET.Direct3D11;
using Silk.NET.DXGI;
using Silk.NET.Vulkan;
using Silk.NET.Vulkan.Extensions.EXT;
using Silk.NET.Vulkan.Extensions.KHR;
using SilkNetDemo;
using SkiaSharp;
using D3DDevice = SharpDX.Direct3D11.Device;
#pragma warning disable CS0162 // Unreachable code detected
namespace GpuInterop.VulkanDemo;
@ -30,7 +32,7 @@ public unsafe class VulkanContext : IDisposable
public required VulkanCommandBufferPool Pool { get; init; }
public required GRContext? GrContext { get; init; }
public required DescriptorPool DescriptorPool { get; init; }
public required D3DDevice? D3DDevice { get; init; }
public required ComPtr<ID3D11Device> D3DDevice { get; init; }
public static (VulkanContext? result, string info) TryCreate(ICompositionGpuInterop gpuInterop)
{
@ -79,7 +81,8 @@ public unsafe class VulkanContext : IDisposable
enabledLayers.Clear();
using var pRequiredExtensions = new ByteStringList(enabledExtensions);
using var pEnabledLayers = new ByteStringList(enabledLayers);
api.CreateInstance(new InstanceCreateInfo
var instanceCreateInfo = new InstanceCreateInfo
{
SType = StructureType.InstanceCreateInfo,
PApplicationInfo = &applicationInfo,
@ -88,7 +91,9 @@ public unsafe class VulkanContext : IDisposable
PpEnabledLayerNames = pEnabledLayers,
EnabledLayerCount = pEnabledLayers.UCount,
Flags = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? InstanceCreateFlags.EnumeratePortabilityBitKhr : default
}, null, out var vkInstance).ThrowOnError();
};
api.CreateInstance(in instanceCreateInfo, null, out var vkInstance).ThrowOnError();
if (api.TryGetInstanceExtension(vkInstance, out ExtDebugUtils debugUtils))
@ -105,7 +110,7 @@ public unsafe class VulkanContext : IDisposable
PfnUserCallback = new PfnDebugUtilsMessengerCallbackEXT(LogCallback),
};
debugUtils.CreateDebugUtilsMessenger(vkInstance, debugCreateInfo, null, out _);
debugUtils.CreateDebugUtilsMessenger(vkInstance, in debugCreateInfo, null, out _);
}
var requireDeviceExtensions = new List<string>();
@ -273,13 +278,13 @@ public unsafe class VulkanContext : IDisposable
return (null, "Can't create Skia GrContext, device is likely broken");
}
D3DDevice? d3dDevice = null;
ComPtr<ID3D11Device> d3dDevice = null;
if (physicalDeviceIDProperties.DeviceLuidvalid &&
RuntimeInformation.IsOSPlatform(OSPlatform.Windows) &&
!gpuInterop.SupportedImageHandleTypes.Contains(KnownPlatformGraphicsExternalImageHandleTypes.VulkanOpaqueNtHandle)
)
d3dDevice = D3DMemoryHelper.CreateDeviceByLuid(
new Span<byte>(physicalDeviceIDProperties.DeviceLuid, 8));
MemoryMarshal.Read<Luid>(new Span<byte>(physicalDeviceIDProperties.DeviceLuid, 8)));
success = true;
return (new VulkanContext
{
@ -354,20 +359,14 @@ public unsafe class VulkanContext : IDisposable
private const string MacVulkanSdkGlobalPath = "/usr/local/lib/libvulkan.dylib";
class MacLibraryNameContainer : SearchPathContainer
{
public override string Windows64 { get; }
public override string Windows86 { get; }
public override string Linux { get; }
public override string MacOS { get; } = MacVulkanSdkGlobalPath;
}
private static Vk GetApi()
{
if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || !File.Exists(MacVulkanSdkGlobalPath))
return Vk.GetApi();
var ctx = new MultiNativeContext(new INativeContext[2]
{
Vk.CreateDefaultContext(new MacLibraryNameContainer().GetLibraryName()),
Vk.CreateDefaultContext([MacVulkanSdkGlobalPath]),
null!
});
var ret = new Vk(ctx);
@ -383,7 +382,7 @@ public unsafe class VulkanContext : IDisposable
public void Dispose()
{
D3DDevice?.Dispose();
D3DDevice.Dispose();
GrContext?.Dispose();
Pool.Dispose();
Api.DestroyDescriptorPool(Device, DescriptorPool, null);

49
samples/GpuInterop/VulkanDemo/VulkanImage.cs

@ -6,12 +6,15 @@ using System.Runtime.InteropServices;
using Avalonia;
using Avalonia.Platform;
using Avalonia.Vulkan;
using SharpDX.DXGI;
using Silk.NET.Core.Native;
using Silk.NET.Direct3D11;
using Silk.NET.DXGI;
using Silk.NET.Vulkan;
using Silk.NET.Vulkan.Extensions.EXT;
using Silk.NET.Vulkan.Extensions.KHR;
using SilkNetDemo;
using SkiaSharp;
using static Silk.NET.Core.Native.SilkMarshal;
using Device = Silk.NET.Vulkan.Device;
using Format = Silk.NET.Vulkan.Format;
@ -29,7 +32,7 @@ public unsafe class VulkanImage : IDisposable
private ImageUsageFlags _imageUsageFlags { get; }
private ImageView _imageView { get; set; }
private DeviceMemory _imageMemory { get; set; }
private readonly SharpDX.Direct3D11.Texture2D? _d3dTexture2D;
private ComPtr<ID3D11Texture2D> _d3dTexture2D;
internal Image InternalHandle { get; private set; }
internal Format Format { get; }
@ -111,7 +114,7 @@ public unsafe class VulkanImage : IDisposable
};
Api
.CreateImage(_device, imageCreateInfo, null, out var image).ThrowOnError();
.CreateImage(_device, in imageCreateInfo, null, out var image).ThrowOnError();
InternalHandle = image;
if (!exportable || !RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
@ -135,16 +138,16 @@ public unsafe class VulkanImage : IDisposable
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>();
if (vk.D3DDevice.Handle == null)
throw new NotSupportedException("Vulkan D3DDevice wasn't created");
_d3dTexture2D = D3DMemoryHelper.CreateMemoryHandle(vk.D3DDevice, size, Format);
handleImport = new ImportMemoryWin32HandleInfoKHR
{
PNext = &dedicatedAllocation,
SType = StructureType.ImportMemoryWin32HandleInfoKhr,
HandleType = ExternalMemoryHandleTypeFlags.D3D11TextureBit,
Handle = dxgi.CreateSharedHandle(null, SharedResourceFlags.Read | SharedResourceFlags.Write),
Handle = CreateDxgiSharedHandle()
};
}
@ -160,7 +163,7 @@ public unsafe class VulkanImage : IDisposable
memoryRequirements.MemoryTypeBits, MemoryPropertyFlags.DeviceLocalBit)
};
Api.AllocateMemory(_device, memoryAllocateInfo, null,
Api.AllocateMemory(_device, in memoryAllocateInfo, null,
out var imageMemory).ThrowOnError();
_imageMemory = imageMemory;
@ -192,7 +195,7 @@ public unsafe class VulkanImage : IDisposable
};
Api
.CreateImageView(_device, imageViewCreateInfo, null, out var imageView)
.CreateImageView(_device, in imageViewCreateInfo, null, out var imageView)
.ThrowOnError();
_imageView = imageView;
@ -202,6 +205,20 @@ public unsafe class VulkanImage : IDisposable
TransitionLayout(ImageLayout.ColorAttachmentOptimal, AccessFlags.NoneKhr);
}
private IntPtr CreateDxgiSharedHandle()
{
using var dxgiResource = _d3dTexture2D.QueryInterface<IDXGIResource1>();
void* sharedHandle;
ThrowHResult(dxgiResource.CreateSharedHandle(
(SecurityAttributes*) null,
DXGI.SharedResourceRead | DXGI.SharedResourceWrite,
(char*)null,
&sharedHandle));
return (IntPtr)sharedHandle;
}
public int ExportFd()
{
if (!Api.TryGetDeviceExtension<KhrExternalMemoryFd>(_instance, _device, out var ext))
@ -212,7 +229,7 @@ public unsafe class VulkanImage : IDisposable
SType = StructureType.MemoryGetFDInfoKhr,
HandleType = ExternalMemoryHandleTypeFlags.OpaqueFDBit
};
ext.GetMemoryF(_device, info, out var fd).ThrowOnError();
ext.GetMemoryF(_device, in info, out var fd).ThrowOnError();
return fd;
}
@ -226,7 +243,7 @@ public unsafe class VulkanImage : IDisposable
SType = StructureType.MemoryGetWin32HandleInfoKhr,
HandleType = ExternalMemoryHandleTypeFlags.OpaqueWin32Bit
};
ext.GetMemoryWin32Handle(_device, info, out var fd).ThrowOnError();
ext.GetMemoryWin32Handle(_device, in info, out var fd).ThrowOnError();
return fd;
}
@ -254,11 +271,10 @@ public unsafe class VulkanImage : IDisposable
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
if (_d3dTexture2D != null)
if (_d3dTexture2D.Handle != null)
{
using var dxgi = _d3dTexture2D!.QueryInterface<Resource1>();
return new PlatformHandle(
dxgi.CreateSharedHandle(null, SharedResourceFlags.Read | SharedResourceFlags.Write),
CreateDxgiSharedHandle(),
KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureNtHandle);
}
@ -275,7 +291,7 @@ public unsafe class VulkanImage : IDisposable
public ImageTiling Tiling => ImageTiling.Optimal;
public bool IsDirectXBacked => _d3dTexture2D != null;
public bool IsDirectXBacked => _d3dTexture2D.Handle != null;
internal void TransitionLayout(CommandBuffer commandBuffer,
ImageLayout fromLayout, AccessFlags fromAccessFlags,
@ -367,8 +383,7 @@ public unsafe class VulkanImage : IDisposable
}
};
using (var backendTexture = new GRBackendRenderTarget(_image.Size.Width, _image.Size.Height, 1,
imageInfo))
using (var backendTexture = new GRBackendRenderTarget(_image.Size.Width, _image.Size.Height, imageInfo))
using (var surface = SKSurface.Create(_vk.GrContext, backendTexture,
GRSurfaceOrigin.TopLeft,
SKColorType.Rgba8888, SKColorSpace.CreateSrgb()))

2
samples/GpuInterop/VulkanDemo/VulkanMemoryHelper.cs

@ -54,6 +54,6 @@ internal static class VulkanMemoryHelper
0,
null,
1,
barrier);
in barrier);
}
}

8
samples/GpuInterop/VulkanDemo/VulkanSemaphorePair.cs

@ -29,10 +29,10 @@ class VulkanSemaphorePair : IDisposable
PNext = exportable ? &semaphoreExportInfo : null
};
resources.Api.CreateSemaphore(resources.Device, semaphoreCreateInfo, null, out var semaphore).ThrowOnError();
resources.Api.CreateSemaphore(resources.Device, in semaphoreCreateInfo, null, out var semaphore).ThrowOnError();
ImageAvailableSemaphore = semaphore;
resources.Api.CreateSemaphore(resources.Device, semaphoreCreateInfo, null, out semaphore).ThrowOnError();
resources.Api.CreateSemaphore(resources.Device, in semaphoreCreateInfo, null, out semaphore).ThrowOnError();
RenderFinishedSemaphore = semaphore;
}
@ -47,7 +47,7 @@ class VulkanSemaphorePair : IDisposable
Semaphore = renderFinished ? RenderFinishedSemaphore : ImageAvailableSemaphore,
HandleType = ExternalSemaphoreHandleTypeFlags.OpaqueFDBit
};
ext.GetSemaphoreF(_resources.Device, info, out var fd).ThrowOnError();
ext.GetSemaphoreF(_resources.Device, in info, out var fd).ThrowOnError();
return fd;
}
@ -62,7 +62,7 @@ class VulkanSemaphorePair : IDisposable
Semaphore = renderFinished ? RenderFinishedSemaphore : ImageAvailableSemaphore,
HandleType = ExternalSemaphoreHandleTypeFlags.OpaqueWin32Bit
};
ext.GetSemaphoreWin32Handle(_resources.Device, info, out var fd).ThrowOnError();
ext.GetSemaphoreWin32Handle(_resources.Device, in info, out var fd).ThrowOnError();
return fd;
}

8
samples/GpuInterop/VulkanDemo/VulkanSwapchain.cs

@ -119,7 +119,7 @@ class VulkanSwapchainImage : ISwapchainImage
buffer.Submit();
}
else
buffer.Submit(new[] { _semaphorePair.ImageAvailableSemaphore },
buffer.Submit(new[] { _semaphorePair!.ImageAvailableSemaphore },
new[]
{
PipelineStageFlags.AllGraphicsBit
@ -160,7 +160,7 @@ class VulkanSwapchainImage : ISwapchainImage
}
}
else
buffer.Submit(null, null, new[] { _semaphorePair.RenderFinishedSemaphore });
buffer.Submit(null, null, new[] { _semaphorePair!.RenderFinishedSemaphore });
if (_timelineSemaphore != null)
{
@ -168,9 +168,9 @@ class VulkanSwapchainImage : ISwapchainImage
}
else if (!_image.IsDirectXBacked)
{
_availableSemaphore ??= _interop.ImportSemaphore(_semaphorePair.Export(false));
_availableSemaphore ??= _interop.ImportSemaphore(_semaphorePair!.Export(false));
_renderCompletedSemaphore ??= _interop.ImportSemaphore(_semaphorePair.Export(true));
_renderCompletedSemaphore ??= _interop.ImportSemaphore(_semaphorePair!.Export(true));
}
_importedImage ??= _interop.ImportImage(_image.Export(),

2
samples/GpuInterop/VulkanDemo/VulkanTimelineSemaphore.cs

@ -32,7 +32,7 @@ class VulkanTimelineSemaphore : IDisposable
SType = StructureType.SemaphoreCreateInfo,
PNext = &semaphoreTypeInfo,
};
resources.Api.CreateSemaphore(resources.Device, semaphoreCreateInfo, null, out var semaphore).ThrowOnError();
resources.Api.CreateSemaphore(resources.Device, in semaphoreCreateInfo, null, out var semaphore).ThrowOnError();
Handle = semaphore;
}

Loading…
Cancel
Save