From 4357a8dafcd54a04469c76b045436a9c2abfa222 Mon Sep 17 00:00:00 2001 From: Julien Lebosquain Date: Mon, 24 Nov 2025 13:23:07 +0100 Subject: [PATCH] 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 --- samples/GpuInterop/App.axaml.cs | 4 +- .../GpuInterop/D3DDemo/D3D11DemoControl.cs | 187 ++++++++------- samples/GpuInterop/D3DDemo/D3D11Swapchain.cs | 80 ++++--- samples/GpuInterop/D3DDemo/D3DContent.cs | 224 +++++++++++------- samples/GpuInterop/DemoType.cs | 7 + samples/GpuInterop/GpuInterop.csproj | 14 +- samples/GpuInterop/MainWindow.axaml | 10 +- samples/GpuInterop/MainWindow.axaml.cs | 22 +- samples/GpuInterop/Program.cs | 32 ++- .../GpuInterop/Properties/launchSettings.json | 12 + .../GpuInterop/VulkanDemo/D3DMemoryHelper.cs | 117 ++++++--- .../VulkanDemo/VulkanBufferHelper.cs | 4 +- .../VulkanDemo/VulkanCommandBufferPool.cs | 18 +- .../GpuInterop/VulkanDemo/VulkanContent.cs | 43 ++-- .../GpuInterop/VulkanDemo/VulkanContext.cs | 33 ++- samples/GpuInterop/VulkanDemo/VulkanImage.cs | 49 ++-- .../VulkanDemo/VulkanMemoryHelper.cs | 2 +- .../VulkanDemo/VulkanSemaphorePair.cs | 8 +- .../GpuInterop/VulkanDemo/VulkanSwapchain.cs | 8 +- .../VulkanDemo/VulkanTimelineSemaphore.cs | 2 +- 20 files changed, 531 insertions(+), 345 deletions(-) create mode 100644 samples/GpuInterop/DemoType.cs create mode 100644 samples/GpuInterop/Properties/launchSettings.json diff --git a/samples/GpuInterop/App.axaml.cs b/samples/GpuInterop/App.axaml.cs index 85973d59bb..8d262ce3c0 100644 --- a/samples/GpuInterop/App.axaml.cs +++ b/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); } } } diff --git a/samples/GpuInterop/D3DDemo/D3D11DemoControl.cs b/samples/GpuInterop/D3DDemo/D3D11DemoControl.cs index 887ddaf654..6511b7b3a9 100644 --- a/samples/GpuInterop/D3DDemo/D3D11DemoControl.cs +++ b/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 _device; private D3D11Swapchain? _swapchain; - private DeviceContext? _context; - private Matrix _view; + private ComPtr _context; + private Matrix4x4 _view; private PixelSize _lastSize; - private Texture2D? _depthBuffer; - private DepthStencilView? _depthView; - private Matrix _proj; - private Buffer? _constantBuffer; + private ComPtr _depthBuffer; + private ComPtr _depthView; + private Matrix4x4 _proj; + private ComPtr _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(); + + using ComPtr 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 device = default; + ComPtr 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 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); } } diff --git a/samples/GpuInterop/D3DDemo/D3D11Swapchain.cs b/samples/GpuInterop/D3DDemo/D3D11Swapchain.cs index d2cf43ac74..257a4b643f 100644 --- a/samples/GpuInterop/D3DDemo/D3D11Swapchain.cs +++ b/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 { - private readonly D3DDevice _device; + private readonly ComPtr _device; - public D3D11Swapchain(D3DDevice device, ICompositionGpuInterop interop, CompositionDrawingSurface target) + public D3D11Swapchain(ComPtr device, ICompositionGpuInterop interop, CompositionDrawingSurface target) : base(interop, target) { _device = device; @@ -24,7 +24,7 @@ class D3D11Swapchain : SwapchainBase 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 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 _texture; + private ComPtr _mutex; + private ComPtr _renderTargetView; private readonly IntPtr _handle; private PlatformGraphicsExternalImageProperties _properties; private ICompositionImportedGpuImage? _imported; + public Task? LastPresent { get; private set; } - public RenderTargetView RenderTargetView { get; } + public ComPtr RenderTargetView => _renderTargetView; - public D3D11SwapchainImage(D3DDevice device, PixelSize size, + public unsafe D3D11SwapchainImage( + ComPtr 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(); - using (var res = _texture.QueryInterface()) - _handle = res.SharedHandle; + + ComPtr 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(); + using (var res = _texture.QueryInterface()) + { + 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(); } -} \ No newline at end of file +} diff --git a/samples/GpuInterop/D3DDemo/D3DContent.cs b/samples/GpuInterop/D3DDemo/D3DContent.cs index f670a9a8c9..01553f60b7 100644 --- a/samples/GpuInterop/D3DDemo/D3DContent.cs +++ b/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 CreateMesh(ComPtr 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 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 pixelShader = default; + ThrowHResult(device.CreatePixelShader( + pixelShaderByteCode.GetBufferPointer(), + pixelShaderByteCode.GetBufferSize(), + (ID3D11ClassLinkage*)null, + pixelShader.GetAddressOf())); - var signature = ShaderSignature.GetInputSignature(vertexShaderByteCode); + using ComPtr vertexShaderSignature = default; + ThrowHResult(s_compiler.GetInputSignatureBlob( + vertexShaderByteCode.GetBufferPointer(), + vertexShaderByteCode.GetBufferSize(), + vertexShaderSignature.GetAddressOf())); - var inputElements = new[] + // Layout from VertexShader input signature + using ComPtr 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 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(), ResourceUsage.Default, - BindFlags.ConstantBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0); - - var context = device.ImmediateContext; + ComPtr 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() * 2, 0)); - context.VertexShader.SetConstantBuffer(0, constantBuffer); - context.VertexShader.Set(vertexShader); - context.PixelShader.Set(pixelShader); + using ComPtr 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 CompileShader(string fileName, string entryPoint, string profile) + { + ComPtr blob = default; + ThrowHResult(s_compiler.CompileFromFile(fileName, null, null, entryPoint, profile, 0u, 0u, blob.GetAddressOf(), null)); + return blob; + } } diff --git a/samples/GpuInterop/DemoType.cs b/samples/GpuInterop/DemoType.cs new file mode 100644 index 0000000000..9dfa72e306 --- /dev/null +++ b/samples/GpuInterop/DemoType.cs @@ -0,0 +1,7 @@ +namespace GpuInterop; + +public enum DemoType +{ + Vulkan, + D3D11 +} diff --git a/samples/GpuInterop/GpuInterop.csproj b/samples/GpuInterop/GpuInterop.csproj index d8fd135ebd..ebf1d38a73 100644 --- a/samples/GpuInterop/GpuInterop.csproj +++ b/samples/GpuInterop/GpuInterop.csproj @@ -7,7 +7,6 @@ enable false true - true true @@ -25,10 +24,13 @@ - - - - + + + + + + + @@ -37,6 +39,7 @@ + @@ -47,5 +50,4 @@ - diff --git a/samples/GpuInterop/MainWindow.axaml b/samples/GpuInterop/MainWindow.axaml index afb025ec27..3c97f3f8ef 100644 --- a/samples/GpuInterop/MainWindow.axaml +++ b/samples/GpuInterop/MainWindow.axaml @@ -1,13 +1,5 @@ - - - - - - + diff --git a/samples/GpuInterop/MainWindow.axaml.cs b/samples/GpuInterop/MainWindow.axaml.cs index 8d359fe7ef..0cb3732b74 100644 --- a/samples/GpuInterop/MainWindow.axaml.cs +++ b/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; } diff --git a/samples/GpuInterop/Program.cs b/samples/GpuInterop/Program.cs index e07780f80b..ef1b9c8951 100644 --- a/samples/GpuInterop/Program.cs +++ b/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() + 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 } diff --git a/samples/GpuInterop/Properties/launchSettings.json b/samples/GpuInterop/Properties/launchSettings.json new file mode 100644 index 0000000000..3cc680c6e8 --- /dev/null +++ b/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" + } + } +} diff --git a/samples/GpuInterop/VulkanDemo/D3DMemoryHelper.cs b/samples/GpuInterop/VulkanDemo/D3DMemoryHelper.cs index 9795c57d5a..e91dcc1d7c 100644 --- a/samples/GpuInterop/VulkanDemo/D3DMemoryHelper.cs +++ b/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 luid) + private const int DxgiErrorNotFound = unchecked((int)0x887A0002); + + public static unsafe ComPtr CreateDeviceByLuid(Luid luid) { - var factory = new DxgiFactory1(); - var longLuid = MemoryMarshal.Cast(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(); + 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 device = default; + ComPtr 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 GetAdapterByLuid(ComPtr factory, Luid luid) + { + var index = 0u; + ComPtr 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 CreateMemoryHandle(ComPtr 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 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; } diff --git a/samples/GpuInterop/VulkanDemo/VulkanBufferHelper.cs b/samples/GpuInterop/VulkanDemo/VulkanBufferHelper.cs index 290eb06b1e..a86477ee9b 100644 --- a/samples/GpuInterop/VulkanDemo/VulkanBufferHelper.cs +++ b/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); } diff --git a/samples/GpuInterop/VulkanDemo/VulkanCommandBufferPool.cs b/samples/GpuInterop/VulkanDemo/VulkanCommandBufferPool.cs index 08df0fe7be..eb3c95ee34 100644 --- a/samples/GpuInterop/VulkanDemo/VulkanCommandBufferPool.cs +++ b/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); } } diff --git a/samples/GpuInterop/VulkanDemo/VulkanContent.cs b/samples/GpuInterop/VulkanDemo/VulkanContent.cs index 73042ad8ba..b132a81c1b 100644 --- a/samples/GpuInterop/VulkanDemo/VulkanContent.cs +++ b/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(), &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(); } diff --git a/samples/GpuInterop/VulkanDemo/VulkanContext.cs b/samples/GpuInterop/VulkanDemo/VulkanContext.cs index e3957b1fea..e5a6227d8d 100644 --- a/samples/GpuInterop/VulkanDemo/VulkanContext.cs +++ b/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 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(); @@ -273,13 +278,13 @@ public unsafe class VulkanContext : IDisposable return (null, "Can't create Skia GrContext, device is likely broken"); } - D3DDevice? d3dDevice = null; + ComPtr d3dDevice = null; if (physicalDeviceIDProperties.DeviceLuidvalid && RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && !gpuInterop.SupportedImageHandleTypes.Contains(KnownPlatformGraphicsExternalImageHandleTypes.VulkanOpaqueNtHandle) ) d3dDevice = D3DMemoryHelper.CreateDeviceByLuid( - new Span(physicalDeviceIDProperties.DeviceLuid, 8)); + MemoryMarshal.Read(new Span(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); diff --git a/samples/GpuInterop/VulkanDemo/VulkanImage.cs b/samples/GpuInterop/VulkanDemo/VulkanImage.cs index 3f3c0b212c..216cb3f815 100644 --- a/samples/GpuInterop/VulkanDemo/VulkanImage.cs +++ b/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 _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(); + 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(); + + void* sharedHandle; + ThrowHResult(dxgiResource.CreateSharedHandle( + (SecurityAttributes*) null, + DXGI.SharedResourceRead | DXGI.SharedResourceWrite, + (char*)null, + &sharedHandle)); + + return (IntPtr)sharedHandle; + } + public int ExportFd() { if (!Api.TryGetDeviceExtension(_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(); 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())) diff --git a/samples/GpuInterop/VulkanDemo/VulkanMemoryHelper.cs b/samples/GpuInterop/VulkanDemo/VulkanMemoryHelper.cs index b7c7b9cf44..0174153097 100644 --- a/samples/GpuInterop/VulkanDemo/VulkanMemoryHelper.cs +++ b/samples/GpuInterop/VulkanDemo/VulkanMemoryHelper.cs @@ -54,6 +54,6 @@ internal static class VulkanMemoryHelper 0, null, 1, - barrier); + in barrier); } } diff --git a/samples/GpuInterop/VulkanDemo/VulkanSemaphorePair.cs b/samples/GpuInterop/VulkanDemo/VulkanSemaphorePair.cs index 163a39dd9e..b4c0ed7a99 100644 --- a/samples/GpuInterop/VulkanDemo/VulkanSemaphorePair.cs +++ b/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; } diff --git a/samples/GpuInterop/VulkanDemo/VulkanSwapchain.cs b/samples/GpuInterop/VulkanDemo/VulkanSwapchain.cs index 323d9b4091..4601b36600 100644 --- a/samples/GpuInterop/VulkanDemo/VulkanSwapchain.cs +++ b/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(), diff --git a/samples/GpuInterop/VulkanDemo/VulkanTimelineSemaphore.cs b/samples/GpuInterop/VulkanDemo/VulkanTimelineSemaphore.cs index 3ce8ab307e..ac9eadacd3 100644 --- a/samples/GpuInterop/VulkanDemo/VulkanTimelineSemaphore.cs +++ b/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; }