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 class App : Application
{ {
public DemoType DemoType { get; set; }
public override void Initialize() public override void Initialize()
{ {
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
@ -15,7 +17,7 @@ namespace GpuInterop
{ {
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktopLifetime) 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;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Rendering.Composition; using Avalonia.Rendering.Composition;
using SharpDX; using Silk.NET.Core.Native;
using SharpDX.Direct3D11; using Silk.NET.Direct3D11;
using SharpDX.DXGI; using Silk.NET.DXGI;
using SharpDX.Mathematics.Interop; using static Silk.NET.Core.Native.SilkMarshal;
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;
namespace GpuInterop.D3DDemo; namespace GpuInterop.D3DDemo;
public class D3D11DemoControl : DrawingSurfaceDemoBase public class D3D11DemoControl : DrawingSurfaceDemoBase
{ {
private D3DDevice? _device; private ComPtr<ID3D11Device> _device;
private D3D11Swapchain? _swapchain; private D3D11Swapchain? _swapchain;
private DeviceContext? _context; private ComPtr<ID3D11DeviceContext> _context;
private Matrix _view; private Matrix4x4 _view;
private PixelSize _lastSize; private PixelSize _lastSize;
private Texture2D? _depthBuffer; private ComPtr<ID3D11Texture2D> _depthBuffer;
private DepthStencilView? _depthView; private ComPtr<ID3D11DepthStencilView> _depthView;
private Matrix _proj; private Matrix4x4 _proj;
private Buffer? _constantBuffer; private ComPtr<ID3D11Buffer> _constantBuffer;
private readonly Stopwatch _st = Stopwatch.StartNew(); 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) CompositionDrawingSurface surface, ICompositionGpuInterop interop)
{ {
if (interop.SupportedImageHandleTypes.Contains(KnownPlatformGraphicsExternalImageHandleTypes if (interop.SupportedImageHandleTypes.Contains(KnownPlatformGraphicsExternalImageHandleTypes
.D3D11TextureGlobalSharedHandle) != true) .D3D11TextureGlobalSharedHandle) != true)
return (false, "DXGI shared handle import is not supported by the current graphics backend"); return (false, "DXGI shared handle import is not supported by the current graphics backend");
var factory = new DxgiFactory1(); using var dxgi = new DXGI(DXGI.CreateDefaultContext(["DXGI.dll"]));
using var adapter = factory.GetAdapter1(0); using var d3d11 = new D3D11(D3D11.CreateDefaultContext(["d3d11.dll"]));
_device = new D3DDevice(adapter, DeviceCreationFlags.None, new[] 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, D3DFeatureLevel.Level121,
FeatureLevel.Level_12_0, D3DFeatureLevel.Level120,
FeatureLevel.Level_11_1, D3DFeatureLevel.Level111,
FeatureLevel.Level_11_0, D3DFeatureLevel.Level110,
FeatureLevel.Level_10_0, D3DFeatureLevel.Level100,
FeatureLevel.Level_9_3, D3DFeatureLevel.Level93,
FeatureLevel.Level_9_2, D3DFeatureLevel.Level92,
FeatureLevel.Level_9_1, D3DFeatureLevel.Level91
}); };
_swapchain = new D3D11Swapchain(_device, interop, surface);
_context = _device.ImmediateContext; 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); _constantBuffer = D3DContent.CreateMesh(_device);
_view = Matrix.LookAtLH(new Vector3(0, 0, -5), new Vector3(0, 0, 0), Vector3.UnitY); _view = Matrix4x4.CreateLookAtLeftHanded(new Vector3(0, 0, -5), new Vector3(0, 0, 0), Vector3.UnitY);
return (true, $"D3D11 ({_device.FeatureLevel}) {adapter.Description1.Description}");
AdapterDesc adapterDesc;
ThrowHResult(adapter.GetDesc(&adapterDesc));
var description = PtrToString((IntPtr)adapterDesc.Description, NativeStringEncoding.LPWStr);
return (true, $"D3D11 ({actualFeatureLevel}) {description}");
} }
protected override void FreeGraphicsResources() protected override void FreeGraphicsResources()
@ -66,16 +88,16 @@ public class D3D11DemoControl : DrawingSurfaceDemoBase
_swapchain = null; _swapchain = null;
} }
Utilities.Dispose(ref _depthView); _depthView.Dispose();
Utilities.Dispose(ref _depthBuffer); _depthBuffer.Dispose();
Utilities.Dispose(ref _constantBuffer); _constantBuffer.Dispose();
Utilities.Dispose(ref _context); _context.Dispose();
Utilities.Dispose(ref _device); _device.Dispose();
} }
protected override bool SupportsDisco => true; protected override bool SupportsDisco => true;
protected override void RenderFrame(PixelSize pixelSize) protected override unsafe void RenderFrame(PixelSize pixelSize)
{ {
if (pixelSize == default) if (pixelSize == default)
return; return;
@ -86,69 +108,70 @@ public class D3D11DemoControl : DrawingSurfaceDemoBase
} }
using (_swapchain!.BeginDraw(pixelSize, out var renderView)) using (_swapchain!.BeginDraw(pixelSize, out var renderView))
{ {
var renderViewHandle = renderView.Handle;
_device!.ImmediateContext.OutputMerger.SetTargets(_depthView, renderView); _context.OMSetRenderTargets(1, &renderViewHandle, _depthView);
var viewProj = Matrix.Multiply(_view, _proj); var viewProj = _view * _proj;
var context = _device.ImmediateContext;
var now = _st.Elapsed.TotalSeconds * 5; var now = _st.Elapsed.TotalSeconds * 5;
var scaleX = (float)(1f + Disco * (Math.Sin(now) + 1) / 6); var scaleX = (float)(1f + Disco * (Math.Sin(now) + 1) / 6);
var scaleY = (float)(1f + Disco * (Math.Cos(now) + 1) / 8); var scaleY = (float)(1f + Disco * (Math.Cos(now) + 1) / 8);
var colorOff =(float) (Math.Sin(now) + 1) / 2 * Disco; var colorOff =(float) (Math.Sin(now) + 1) / 2 * Disco;
// Clear views // Clear views
context.ClearDepthStencilView(_depthView, DepthStencilClearFlags.Depth, 1.0f, 0); _context.ClearDepthStencilView(_depthView, (uint)ClearFlag.Depth, 1.0f, 0);
context.ClearRenderTargetView(renderView, var color = new Vector4(1f - colorOff, colorOff, 0.5f + colorOff * 0.5f, 1.0f);
new RawColor4(1 - colorOff, colorOff, (float)0.5 + colorOff / 2, 1)); _context.ClearRenderTargetView(renderView, (float*)&color);
var ypr = Matrix4x4.CreateFromYawPitchRoll(Yaw, Pitch, Roll);
// Update WorldViewProj Matrix // Update WorldViewProj Matrix
var worldViewProj = Matrix.RotationX(Yaw) * Matrix.RotationY(Pitch) var ypr = Matrix4x4.CreateFromYawPitchRoll(Yaw, Pitch, Roll);
* Matrix.RotationZ(Roll) var worldViewProj = ypr * Matrix4x4.CreateScale(new Vector3(scaleX, scaleY, 1)) * viewProj;
* Matrix.Scaling(new Vector3(scaleX, scaleY, 1)) worldViewProj = Matrix4x4.Transpose(worldViewProj);
* viewProj;
worldViewProj.Transpose(); _context.UpdateSubresource(_constantBuffer, 0, null, &worldViewProj, 0, 0);
context.UpdateSubresource(ref worldViewProj, _constantBuffer);
// Draw the cube // 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; return;
_depthBuffer = new Texture2D(_device, ComPtr<ID3D11Texture2D> depthBuffer = default;
new Texture2DDescription() var textureDesc = new Texture2DDesc
{ {
Format = Format.D32_Float_S8X24_UInt, Format = Format.FormatD32FloatS8X24Uint,
ArraySize = 1, ArraySize = 1,
MipLevels = 1, MipLevels = 1,
Width = size.Width, Width = (uint)size.Width,
Height = size.Height, Height = (uint)size.Height,
SampleDescription = new SampleDescription(1, 0), SampleDesc = new SampleDesc(1, 0),
Usage = ResourceUsage.Default, Usage = Usage.Default,
BindFlags = BindFlags.DepthStencil, BindFlags = (uint)BindFlag.DepthStencil,
CpuAccessFlags = CpuAccessFlags.None, CPUAccessFlags = (uint)CpuAccessFlag.None,
OptionFlags = ResourceOptionFlags.None MiscFlags = (uint)ResourceMiscFlag.None
}); };
ThrowHResult(_device.CreateTexture2D(
Utilities.Dispose(ref _depthView); &textureDesc,
_depthView = new DepthStencilView(_device, _depthBuffer); (SubresourceData*)null,
depthBuffer.GetAddressOf()));
_depthBuffer = depthBuffer;
_depthView.Dispose();
ThrowHResult(_device.CreateDepthStencilView(_depthBuffer, null, ref _depthView));
// Setup targets and viewport for rendering // 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 // 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;
using System.Runtime.CompilerServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia; using Avalonia;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Rendering; using Avalonia.Rendering;
using Avalonia.Rendering.Composition; using Avalonia.Rendering.Composition;
using SharpDX.Direct3D11; using Silk.NET.Core.Native;
using SharpDX.DXGI; using Silk.NET.Direct3D11;
using DxgiFactory1 = SharpDX.DXGI.Factory1; using Silk.NET.DXGI;
using D3DDevice = SharpDX.Direct3D11.Device; using static Silk.NET.Core.Native.SilkMarshal;
using DxgiResource = SharpDX.DXGI.Resource;
namespace GpuInterop.D3DDemo; namespace GpuInterop.D3DDemo;
class D3D11Swapchain : SwapchainBase<D3D11SwapchainImage> 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) : base(interop, target)
{ {
_device = device; _device = device;
@ -24,7 +24,7 @@ class D3D11Swapchain : SwapchainBase<D3D11SwapchainImage>
protected override D3D11SwapchainImage CreateImage(PixelSize size) => new(_device, size, Interop, Target); 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); var rv = BeginDrawCore(size, out var image);
view = image.RenderTargetView; view = image.RenderTargetView;
@ -37,53 +37,67 @@ public class D3D11SwapchainImage : ISwapchainImage
public PixelSize Size { get; } public PixelSize Size { get; }
private readonly ICompositionGpuInterop _interop; private readonly ICompositionGpuInterop _interop;
private readonly CompositionDrawingSurface _target; private readonly CompositionDrawingSurface _target;
private readonly Texture2D _texture; private ComPtr<ID3D11Texture2D> _texture;
private readonly KeyedMutex _mutex; private ComPtr<IDXGIKeyedMutex> _mutex;
private ComPtr<ID3D11RenderTargetView> _renderTargetView;
private readonly IntPtr _handle; private readonly IntPtr _handle;
private PlatformGraphicsExternalImageProperties _properties; private PlatformGraphicsExternalImageProperties _properties;
private ICompositionImportedGpuImage? _imported; private ICompositionImportedGpuImage? _imported;
public Task? LastPresent { get; private set; } 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, ICompositionGpuInterop interop,
CompositionDrawingSurface target) CompositionDrawingSurface target)
{ {
Size = size; Size = size;
_interop = interop; _interop = interop;
_target = target; _target = target;
_texture = new Texture2D(device,
new Texture2DDescription ComPtr<ID3D11Texture2D> texture = default;
{ var textureDesc = new Texture2DDesc
Format = Format.R8G8B8A8_UNorm, {
Width = size.Width, Format = Format.FormatR8G8B8A8Unorm,
Height = size.Height, Width = (uint)size.Width,
ArraySize = 1, Height = (uint)size.Height,
MipLevels = 1, ArraySize = 1,
SampleDescription = new SampleDescription { Count = 1, Quality = 0 }, MipLevels = 1,
CpuAccessFlags = default, SampleDesc = new SampleDesc(1, 0),
OptionFlags = ResourceOptionFlags.SharedKeyedmutex, Usage = Usage.Default,
BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource BindFlags = (uint)(BindFlag.RenderTarget | BindFlag.ShaderResource),
}); CPUAccessFlags = 0,
_mutex = _texture.QueryInterface<KeyedMutex>(); MiscFlags = (uint)ResourceMiscFlag.SharedKeyedmutex
using (var res = _texture.QueryInterface<DxgiResource>()) };
_handle = res.SharedHandle; 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 _properties = new PlatformGraphicsExternalImageProperties
{ {
Width = size.Width, Height = size.Height, Format = PlatformGraphicsExternalImageFormat.B8G8R8A8UNorm Width = size.Width, Height = size.Height, Format = PlatformGraphicsExternalImageFormat.B8G8R8A8UNorm
}; };
RenderTargetView = new RenderTargetView(device, _texture); ThrowHResult(device.CreateRenderTargetView(_texture, null, ref _renderTargetView));
} }
public void BeginDraw() public void BeginDraw()
{ {
_mutex.Acquire(0, int.MaxValue); _mutex.AcquireSync(0, int.MaxValue);
} }
public void Present() public void Present()
{ {
_mutex.Release(1); _mutex.ReleaseSync(1);
_imported ??= _interop.ImportImage( _imported ??= _interop.ImportImage(
new PlatformHandle(_handle, KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureGlobalSharedHandle), new PlatformHandle(_handle, KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureGlobalSharedHandle),
_properties); _properties);
@ -103,8 +117,8 @@ public class D3D11SwapchainImage : ISwapchainImage
// Ignore // Ignore
} }
RenderTargetView.Dispose(); _renderTargetView.Dispose();
_mutex.Dispose(); _mutex.Dispose();
_texture.Dispose(); _texture.Dispose();
} }
} }

224
samples/GpuInterop/D3DDemo/D3DContent.cs

@ -1,110 +1,158 @@
using SharpDX; using System.Numerics;
using SharpDX.D3DCompiler; using Silk.NET.Core.Native;
using SharpDX.Direct3D; using Silk.NET.Direct3D.Compilers;
using Silk.NET.Direct3D11;
using System; using Silk.NET.DXGI;
using System.Linq; using static Silk.NET.Core.Native.SilkMarshal;
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;
namespace GpuInterop.D3DDemo; 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 // Compile Vertex and Pixel shaders
var vertexShaderByteCode = ShaderBytecode.CompileFromFile("D3DDemo\\MiniCube.fx", "VS", "vs_4_0"); using var vertexShaderByteCode = CompileShader("D3DDemo\\MiniCube.fx", "VS", "vs_4_0");
var vertexShader = new VertexShader(device, vertexShaderByteCode); 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"); using var pixelShaderByteCode = CompileShader("D3DDemo\\MiniCube.fx", "PS", "ps_4_0");
var pixelShader = new PixelShader(device, pixelShaderByteCode); 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), const int inputCount = 2;
new InputElement("COLOR", 0, Format.R32G32B32A32_Float, 16, 0) 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 ThrowHResult(device.CreateInputLayout(
var layout = new InputLayout( inputs,
device, inputCount,
signature, vertexShaderSignature.GetBufferPointer(),
inputElements); vertexShaderSignature.GetBufferSize(),
inputLayout.GetAddressOf()));
}
finally
{
FreeString(positionNamePtr, NativeStringEncoding.LPStr);
FreeString(colorNamePtr, NativeStringEncoding.LPStr);
}
// Instantiate Vertex buffer from vertex data // Instantiate Vertex buffer from vertex data
using var vertices = Buffer.Create( var vertices = new[]
device, {
BindFlags.VertexBuffer, new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f), // Front
new[] 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 ByteWidth = (uint)(sizeof(Vector4) * vertices.Length),
new Vector4(-1.0f, 1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f), Usage = Usage.Default,
new Vector4(1.0f, 1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f), BindFlags = (uint)BindFlag.VertexBuffer,
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f), CPUAccessFlags = (uint)CpuAccessFlag.None,
new Vector4(1.0f, 1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f), MiscFlags = (uint)ResourceMiscFlag.None,
new Vector4(1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f), StructureByteStride = 0
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), var subresourceData = new SubresourceData(verticesPtr);
new Vector4(-1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f), ThrowHResult(device.CreateBuffer(&vertexBufferDesc, &subresourceData, vertexBuffer.GetAddressOf()));
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),
});
// Create Constant Buffer // Create Constant Buffer
var constantBuffer = new Buffer(device, Utilities.SizeOf<Matrix>(), ResourceUsage.Default, ComPtr<ID3D11Buffer> constantBuffer = default;
BindFlags.ConstantBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0); var constantBufferDesc = new BufferDesc
{
var context = device.ImmediateContext; 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 // Prepare All the stages
context.InputAssembler.InputLayout = layout; using ComPtr<ID3D11DeviceContext> context = default;
context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList; device.GetImmediateContext(context.GetAddressOf());
context.InputAssembler.SetVertexBuffers(0,
new VertexBufferBinding(vertices, Utilities.SizeOf<Vector4>() * 2, 0)); context.IASetInputLayout(inputLayout);
context.VertexShader.SetConstantBuffer(0, constantBuffer); context.IASetPrimitiveTopology(D3DPrimitiveTopology.D3D10PrimitiveTopologyTrianglelist);
context.VertexShader.Set(vertexShader); var stride = (uint)(sizeof(Vector4) * 2);
context.PixelShader.Set(pixelShader); 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; 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> <Nullable>enable</Nullable>
<GenerateDocumentationFile>false</GenerateDocumentationFile> <GenerateDocumentationFile>false</GenerateDocumentationFile>
<UseD3DCompiler>true</UseD3DCompiler> <UseD3DCompiler>true</UseD3DCompiler>
<UseSharpDXMathematics>true</UseSharpDXMathematics>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
@ -25,10 +24,13 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Silk.NET.Vulkan" Version="2.16.0" /> <PackageReference Include="Silk.NET.Direct3D11" Version="2.22.0" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.16.0" /> <PackageReference Include="Silk.NET.Direct3D.Compilers" Version="2.22.0" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.16.0" /> <PackageReference Include="Silk.NET.Vulkan" Version="2.22.0" />
<PackageReference Include="System.Reactive" Version="5.0.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>
<ItemGroup> <ItemGroup>
@ -37,6 +39,7 @@
<ItemGroup> <ItemGroup>
<Compile Include="..\..\src\Avalonia.Base\Rendering\SwapchainBase.cs" /> <Compile Include="..\..\src\Avalonia.Base\Rendering\SwapchainBase.cs" />
<Compile Include="..\..\src\Avalonia.Base\Reactive\Disposable.cs" />
<None Remove="VulkanDemo\Assets\Shaders\frag.spirv" /> <None Remove="VulkanDemo\Assets\Shaders\frag.spirv" />
<EmbeddedResource Include="VulkanDemo\Assets\Shaders\frag.spirv" /> <EmbeddedResource Include="VulkanDemo\Assets\Shaders\frag.spirv" />
<None Remove="VulkanDemo\Assets\Shaders\vert.spirv" /> <None Remove="VulkanDemo\Assets\Shaders\vert.spirv" />
@ -47,5 +50,4 @@
<Import Project="..\..\build\SampleApp.props" /> <Import Project="..\..\build\SampleApp.props" />
<Import Project="..\..\build\ReferenceCoreLibraries.props" /> <Import Project="..\..\build\ReferenceCoreLibraries.props" />
<Import Project="..\..\build\BuildTargets.targets" /> <Import Project="..\..\build\BuildTargets.targets" />
<Import Project="..\..\build\SharpDX.props" />
</Project> </Project>

10
samples/GpuInterop/MainWindow.axaml

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

22
samples/GpuInterop/MainWindow.axaml.cs

@ -1,15 +1,35 @@
using System;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.Rendering; using Avalonia.Rendering;
using GpuInterop.D3DDemo;
using GpuInterop.VulkanDemo;
namespace GpuInterop namespace GpuInterop
{ {
public class MainWindow : Window public class MainWindow : Window
{ {
public MainWindow() public MainWindow() : this(DemoType.Vulkan)
{
}
public MainWindow(DemoType demoType)
{ {
InitializeComponent(); 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(); this.AttachDevTools();
RendererDiagnostics.DebugOverlays = RendererDebugOverlays.Fps; RendererDiagnostics.DebugOverlays = RendererDebugOverlays.Fps;
} }

32
samples/GpuInterop/Program.cs

@ -1,29 +1,35 @@
global using System.Reactive.Disposables; using System;
using Avalonia; using Avalonia;
using Avalonia.Logging; using Avalonia.Logging;
using Avalonia.Vulkan; using Avalonia.Vulkan;
namespace GpuInterop namespace GpuInterop
{ {
public class Program public static class Program
{ {
static void Main(string[] args) => BuildAvaloniaApp() public static void Main(string[] args)
.StartWithClassicDesktopLifetime(args); {
var demoType = OperatingSystem.IsWindows() && args.AsSpan().Contains("--d3d") ? DemoType.D3D11 : DemoType.Vulkan;
BuildAvaloniaAppCore(demoType).StartWithClassicDesktopLifetime(args);
}
public static AppBuilder BuildAvaloniaApp() => public static AppBuilder BuildAvaloniaApp() => BuildAvaloniaAppCore(DemoType.Vulkan);
AppBuilder.Configure<App>()
private static AppBuilder BuildAvaloniaAppCore(DemoType demoType) =>
AppBuilder
.Configure(() => new App { DemoType = demoType })
.UsePlatformDetect() .UsePlatformDetect()
.With(new Win32PlatformOptions .With(new Win32PlatformOptions
{ {
RenderingMode = new [] RenderingMode = [demoType == DemoType.D3D11 ? Win32RenderingMode.AngleEgl : Win32RenderingMode.Vulkan]
{ })
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 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;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Avalonia; using Avalonia;
using SharpDX.Direct3D; using Silk.NET.Core.Native;
using SharpDX.Direct3D11; using Silk.NET.Direct3D11;
using SharpDX.DXGI; using Silk.NET.DXGI;
using D3DDevice = SharpDX.Direct3D11.Device; using VulkanFormat = Silk.NET.Vulkan.Format;
using DxgiFactory1 = SharpDX.DXGI.Factory1; using static Silk.NET.Core.Native.SilkMarshal;
namespace GpuInterop.VulkanDemo; namespace GpuInterop.VulkanDemo;
public class D3DMemoryHelper 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(); using var dxgi = new DXGI(DXGI.CreateDefaultContext(["DXGI.dll"]));
var longLuid = MemoryMarshal.Cast<byte, long>(luid)[0]; using var d3d11 = new D3D11(D3D11.CreateDefaultContext(["d3d11.dll"]));
for (var c = 0; c < factory.GetAdapterCount1(); c++) 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); D3DFeatureLevel.Level121,
if (adapter.Description1.Luid != longLuid) D3DFeatureLevel.Level120,
continue; D3DFeatureLevel.Level111,
D3DFeatureLevel.Level110,
return new D3DDevice(adapter, DeviceCreationFlags.None, D3DFeatureLevel.Level100,
new[] D3DFeatureLevel.Level93,
{ D3DFeatureLevel.Level92,
FeatureLevel.Level_12_1, FeatureLevel.Level_12_0, FeatureLevel.Level_11_1, D3DFeatureLevel.Level91
FeatureLevel.Level_11_0, FeatureLevel.Level_10_0, FeatureLevel.Level_9_3, };
FeatureLevel.Level_9_2, FeatureLevel.Level_9_1,
}); 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"); 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"); throw new ArgumentException("Not supported format");
return new Texture2D(device,
new Texture2DDescription ComPtr<ID3D11Texture2D> texture = default;
{ var textureDesc = new Texture2DDesc
Format = Format.R8G8B8A8_UNorm, {
Width = size.Width, Format = Format.FormatR8G8B8A8Unorm,
Height = size.Height, Width = (uint)size.Width,
ArraySize = 1, Height = (uint)size.Height,
MipLevels = 1, ArraySize = 1,
SampleDescription = new SampleDescription { Count = 1, Quality = 0 }, MipLevels = 1,
CpuAccessFlags = default, SampleDesc = new SampleDesc(1, 0),
OptionFlags = ResourceOptionFlags.SharedKeyedmutex|ResourceOptionFlags.SharedNthandle, Usage = Usage.Default,
BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource 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, Usage = bufferUsageFlags,
SharingMode = SharingMode.Exclusive 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); api.GetBufferMemoryRequirements(device, buffer, out var memoryRequirements);
@ -42,7 +42,7 @@ static class VulkanBufferHelper
MemoryPropertyFlags.HostVisibleBit) 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); api.BindBufferMemory(device, buffer, memory, 0);
UpdateBufferMemory(vk, memory, initialData); UpdateBufferMemory(vk, memory, initialData);
} }

18
samples/GpuInterop/VulkanDemo/VulkanCommandBufferPool.cs

@ -28,7 +28,7 @@ namespace Avalonia.Vulkan
QueueFamilyIndex = queueFamilyIndex QueueFamilyIndex = queueFamilyIndex
}; };
_api.CreateCommandPool(_device, commandPoolCreateInfo, null, out _commandPool) _api.CreateCommandPool(_device, in commandPoolCreateInfo, null, out _commandPool)
.ThrowOnError(); .ThrowOnError();
} }
@ -53,7 +53,7 @@ namespace Avalonia.Vulkan
lock (_lock) lock (_lock)
{ {
_api.AllocateCommandBuffers(_device, commandBufferAllocateInfo, out var commandBuffer); _api.AllocateCommandBuffers(_device, in commandBufferAllocateInfo, out var commandBuffer);
return commandBuffer; return commandBuffer;
} }
@ -111,15 +111,16 @@ namespace Avalonia.Vulkan
Flags = FenceCreateFlags.SignaledBit Flags = FenceCreateFlags.SignaledBit
}; };
api.CreateFence(device, fenceCreateInfo, null, out _fence); api.CreateFence(device, in fenceCreateInfo, null, out _fence);
} }
public unsafe void Dispose() public unsafe void Dispose()
{ {
_api.WaitForFences(_device, 1, _fence, true, ulong.MaxValue); _api.WaitForFences(_device, 1, in _fence, true, ulong.MaxValue);
lock (_commandBufferPool._lock) 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); _api.DestroyFence(_device, _fence, null);
} }
@ -136,7 +137,7 @@ namespace Avalonia.Vulkan
Flags = CommandBufferUsageFlags.OneTimeSubmitBit Flags = CommandBufferUsageFlags.OneTimeSubmitBit
}; };
_api.BeginCommandBuffer(InternalHandle, beginInfo); _api.BeginCommandBuffer(InternalHandle, in beginInfo);
} }
} }
@ -212,9 +213,10 @@ namespace Avalonia.Vulkan
PSignalSemaphores = pSignalSemaphores, 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, PCode = (uint*)ptr,
}; };
api.CreateShaderModule(device, shaderCreateInfo, null, out _vertShader); api.CreateShaderModule(device, in shaderCreateInfo, null, out _vertShader);
} }
fixed (byte* ptr = fragShaderData) fixed (byte* ptr = fragShaderData)
@ -105,7 +105,7 @@ unsafe class VulkanContent : IDisposable
PCode = (uint*)ptr, PCode = (uint*)ptr,
}; };
api.CreateShaderModule(device, shaderCreateInfo, null, out _fragShader); api.CreateShaderModule(device, in shaderCreateInfo, null, out _fragShader);
} }
CreateBuffers(); CreateBuffers();
@ -160,16 +160,16 @@ unsafe class VulkanContent : IDisposable
var commandBufferHandle = new CommandBuffer(commandBuffer.Handle); var commandBufferHandle = new CommandBuffer(commandBuffer.Handle);
api.CmdSetViewport(commandBufferHandle, 0, 1, var viewport = new Viewport()
new Viewport() {
{ Width = (float)image.Size.Width,
Width = (float)image.Size.Width, Height = (float)image.Size.Height,
Height = (float)image.Size.Height, MaxDepth = 1,
MaxDepth = 1, MinDepth = 0,
MinDepth = 0, X = 0,
X = 0, Y = 0
Y = 0 };
}); api.CmdSetViewport(commandBufferHandle, 0, 1, in viewport);
var scissor = new Rect2D var scissor = new Rect2D
{ {
@ -196,7 +196,7 @@ unsafe class VulkanContent : IDisposable
PClearValues = clearValue PClearValues = clearValue
}; };
api.CmdBeginRenderPass(commandBufferHandle, beginInfo, SubpassContents.Inline); api.CmdBeginRenderPass(commandBufferHandle, in beginInfo, SubpassContents.Inline);
} }
api.CmdBindPipeline(commandBufferHandle, PipelineBindPoint.Graphics, _pipeline); api.CmdBindPipeline(commandBufferHandle, PipelineBindPoint.Graphics, _pipeline);
@ -207,7 +207,8 @@ unsafe class VulkanContent : IDisposable
api.CmdPushConstants(commandBufferHandle, _pipelineLayout, ShaderStageFlags.VertexBit | ShaderStageFlags.FragmentBit, 0, api.CmdPushConstants(commandBufferHandle, _pipelineLayout, ShaderStageFlags.VertexBit | ShaderStageFlags.FragmentBit, 0,
(uint)Marshal.SizeOf<VertexPushConstant>(), &vertexConstant); (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.CmdBindIndexBuffer(commandBufferHandle, _indexBuffer, 0, IndexType.Uint16);
api.CmdDrawIndexed(commandBufferHandle, (uint)_indices.Length, 1, 0, 0, 0); api.CmdDrawIndexed(commandBufferHandle, (uint)_indices.Length, 1, 0, 0, 0);
@ -250,7 +251,7 @@ unsafe class VulkanContent : IDisposable
api.CmdBlitImage(commandBuffer.InternalHandle, _colorAttachment.InternalHandle, api.CmdBlitImage(commandBuffer.InternalHandle, _colorAttachment.InternalHandle,
ImageLayout.TransferSrcOptimal, ImageLayout.TransferSrcOptimal,
image.InternalHandle, ImageLayout.TransferDstOptimal, 1, srcBlitRegion, Filter.Linear); image.InternalHandle, ImageLayout.TransferDstOptimal, 1, in srcBlitRegion, Filter.Linear);
commandBuffer.Submit(); commandBuffer.Submit();
} }
@ -341,7 +342,7 @@ unsafe class VulkanContent : IDisposable
var api = _context.Api; var api = _context.Api;
var device = _context.Device; var device = _context.Device;
api api
.CreateImage(device, imageCreateInfo, null, out _depthImage).ThrowOnError(); .CreateImage(device, in imageCreateInfo, null, out _depthImage).ThrowOnError();
api.GetImageMemoryRequirements(device, _depthImage, api.GetImageMemoryRequirements(device, _depthImage,
out var memoryRequirements); out var memoryRequirements);
@ -355,7 +356,7 @@ unsafe class VulkanContent : IDisposable
memoryRequirements.MemoryTypeBits, MemoryPropertyFlags.DeviceLocalBit) memoryRequirements.MemoryTypeBits, MemoryPropertyFlags.DeviceLocalBit)
}; };
api.AllocateMemory(device, memoryAllocateInfo, null, api.AllocateMemory(device, in memoryAllocateInfo, null,
out _depthImageMemory).ThrowOnError(); out _depthImageMemory).ThrowOnError();
api.BindImageMemory(device, _depthImage, _depthImageMemory, 0); api.BindImageMemory(device, _depthImage, _depthImageMemory, 0);
@ -380,7 +381,7 @@ unsafe class VulkanContent : IDisposable
}; };
api api
.CreateImageView(device, imageViewCreateInfo, null, out _depthImageView) .CreateImageView(device, in imageViewCreateInfo, null, out _depthImageView)
.ThrowOnError(); .ThrowOnError();
} }
@ -467,7 +468,7 @@ unsafe class VulkanContent : IDisposable
PDependencies = &subpassDependency PDependencies = &subpassDependency
}; };
api.CreateRenderPass(device, renderPassCreateInfo, null, out _renderPass).ThrowOnError(); api.CreateRenderPass(device, in renderPassCreateInfo, null, out _renderPass).ThrowOnError();
// create framebuffer // create framebuffer
@ -486,7 +487,7 @@ unsafe class VulkanContent : IDisposable
Layers = 1 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 PSetLayouts = &setLayout
}; };
api.CreatePipelineLayout(device, pipelineLayoutCreateInfo, null, out _pipelineLayout) api.CreatePipelineLayout(device, in pipelineLayoutCreateInfo, null, out _pipelineLayout)
.ThrowOnError(); .ThrowOnError();
} }

33
samples/GpuInterop/VulkanDemo/VulkanContext.cs

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

49
samples/GpuInterop/VulkanDemo/VulkanImage.cs

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

2
samples/GpuInterop/VulkanDemo/VulkanMemoryHelper.cs

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

8
samples/GpuInterop/VulkanDemo/VulkanSemaphorePair.cs

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

8
samples/GpuInterop/VulkanDemo/VulkanSwapchain.cs

@ -119,7 +119,7 @@ class VulkanSwapchainImage : ISwapchainImage
buffer.Submit(); buffer.Submit();
} }
else else
buffer.Submit(new[] { _semaphorePair.ImageAvailableSemaphore }, buffer.Submit(new[] { _semaphorePair!.ImageAvailableSemaphore },
new[] new[]
{ {
PipelineStageFlags.AllGraphicsBit PipelineStageFlags.AllGraphicsBit
@ -160,7 +160,7 @@ class VulkanSwapchainImage : ISwapchainImage
} }
} }
else else
buffer.Submit(null, null, new[] { _semaphorePair.RenderFinishedSemaphore }); buffer.Submit(null, null, new[] { _semaphorePair!.RenderFinishedSemaphore });
if (_timelineSemaphore != null) if (_timelineSemaphore != null)
{ {
@ -168,9 +168,9 @@ class VulkanSwapchainImage : ISwapchainImage
} }
else if (!_image.IsDirectXBacked) 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(), _importedImage ??= _interop.ImportImage(_image.Export(),

2
samples/GpuInterop/VulkanDemo/VulkanTimelineSemaphore.cs

@ -32,7 +32,7 @@ class VulkanTimelineSemaphore : IDisposable
SType = StructureType.SemaphoreCreateInfo, SType = StructureType.SemaphoreCreateInfo,
PNext = &semaphoreTypeInfo, 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; Handle = semaphore;
} }

Loading…
Cancel
Save