D3D11Swapchain.cs 3.7 KB

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