D3D11Swapchain.cs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. using System;
  2. using System.Threading.Tasks;
  3. using Avalonia;
  4. using Avalonia.Platform;
  5. using Avalonia.Rendering;
  6. using Avalonia.Rendering.Composition;
  7. using SharpDX.Direct3D11;
  8. using SharpDX.DXGI;
  9. using DxgiFactory1 = SharpDX.DXGI.Factory1;
  10. using D3DDevice = SharpDX.Direct3D11.Device;
  11. using DxgiResource = SharpDX.DXGI.Resource;
  12. namespace GpuInterop.D3DDemo;
  13. class D3D11Swapchain : SwapchainBase<D3D11SwapchainImage>
  14. {
  15. private readonly D3DDevice _device;
  16. public D3D11Swapchain(D3DDevice device, ICompositionGpuInterop interop, CompositionDrawingSurface target)
  17. : base(interop, target)
  18. {
  19. _device = device;
  20. }
  21. protected override D3D11SwapchainImage CreateImage(PixelSize size) => new(_device, size, Interop, Target);
  22. public IDisposable BeginDraw(PixelSize size, out RenderTargetView view)
  23. {
  24. var rv = BeginDrawCore(size, out var image);
  25. view = image.RenderTargetView;
  26. return rv;
  27. }
  28. }
  29. public class D3D11SwapchainImage : ISwapchainImage
  30. {
  31. public PixelSize Size { get; }
  32. private readonly ICompositionGpuInterop _interop;
  33. private readonly CompositionDrawingSurface _target;
  34. private readonly Texture2D _texture;
  35. private readonly KeyedMutex _mutex;
  36. private readonly IntPtr _handle;
  37. private PlatformGraphicsExternalImageProperties _properties;
  38. private ICompositionImportedGpuImage? _imported;
  39. public Task? LastPresent { get; private set; }
  40. public RenderTargetView RenderTargetView { get; }
  41. public D3D11SwapchainImage(D3DDevice device, PixelSize size,
  42. ICompositionGpuInterop interop,
  43. CompositionDrawingSurface target)
  44. {
  45. Size = size;
  46. _interop = interop;
  47. _target = target;
  48. _texture = new Texture2D(device,
  49. new Texture2DDescription
  50. {
  51. Format = Format.R8G8B8A8_UNorm,
  52. Width = size.Width,
  53. Height = size.Height,
  54. ArraySize = 1,
  55. MipLevels = 1,
  56. SampleDescription = new SampleDescription { Count = 1, Quality = 0 },
  57. CpuAccessFlags = default,
  58. OptionFlags = ResourceOptionFlags.SharedKeyedmutex,
  59. BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource
  60. });
  61. _mutex = _texture.QueryInterface<KeyedMutex>();
  62. using (var res = _texture.QueryInterface<DxgiResource>())
  63. _handle = res.SharedHandle;
  64. _properties = new PlatformGraphicsExternalImageProperties
  65. {
  66. Width = size.Width, Height = size.Height, Format = PlatformGraphicsExternalImageFormat.B8G8R8A8UNorm
  67. };
  68. RenderTargetView = new RenderTargetView(device, _texture);
  69. }
  70. public void BeginDraw()
  71. {
  72. _mutex.Acquire(0, int.MaxValue);
  73. }
  74. public void Present()
  75. {
  76. _mutex.Release(1);
  77. _imported ??= _interop.ImportImage(
  78. new PlatformHandle(_handle, KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureGlobalSharedHandle),
  79. _properties);
  80. LastPresent = _target.UpdateWithKeyedMutexAsync(_imported, 1, 0);
  81. }
  82. public async ValueTask DisposeAsync()
  83. {
  84. if (LastPresent != null)
  85. try
  86. {
  87. await LastPresent;
  88. }
  89. catch
  90. {
  91. // Ignore
  92. }
  93. RenderTargetView.Dispose();
  94. _mutex.Dispose();
  95. _texture.Dispose();
  96. }
  97. }