D3D11Image.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. using System;
  2. using System.Windows;
  3. using System.Windows.Interop;
  4. using Microsoft.Xna.Framework.Graphics;
  5. using SharpDX.Direct3D9;
  6. using Texture = SharpDX.Direct3D9.Texture;
  7. namespace WpfInteropSample
  8. {
  9. /// <summary>
  10. /// Wraps the <see cref="D3DImage"/> to make it compatible with Direct3D 11.
  11. /// </summary>
  12. /// <remarks>
  13. /// The <see cref="D3D11Image"/> should be disposed if no longer needed!
  14. /// </remarks>
  15. internal class D3D11Image : D3DImage, IDisposable
  16. {
  17. // Use a Direct3D 9 device for interoperability. The device is shared by
  18. // all D3D11Images.
  19. private static D3D9 _d3D9;
  20. private static int _referenceCount;
  21. private static readonly object _d3d9Lock = new object();
  22. private bool _disposed;
  23. private Texture _backBuffer;
  24. /// <summary>
  25. /// Initializes a new instance of the <see cref="D3D11Image"/> class.
  26. /// </summary>
  27. public D3D11Image()
  28. {
  29. InitializeD3D9();
  30. }
  31. /// <summary>
  32. /// Releases unmanaged resources before an instance of the <see cref="D3D11Image"/> class is
  33. /// reclaimed by garbage collection.
  34. /// </summary>
  35. /// <remarks>
  36. /// This method releases unmanaged resources by calling the virtual <see cref="Dispose(bool)"/>
  37. /// method, passing in <see langword="false"/>.
  38. /// </remarks>
  39. ~D3D11Image()
  40. {
  41. Dispose(false);
  42. }
  43. /// <summary>
  44. /// Releases all resources used by an instance of the <see cref="D3D11Image"/> class.
  45. /// </summary>
  46. /// <remarks>
  47. /// This method calls the virtual <see cref="Dispose(bool)"/> method, passing in
  48. /// <see langword="true"/>, and then suppresses finalization of the instance.
  49. /// </remarks>
  50. public void Dispose()
  51. {
  52. Dispose(true);
  53. GC.SuppressFinalize(this);
  54. }
  55. /// <summary>
  56. /// Releases the unmanaged resources used by an instance of the <see cref="D3D11Image"/> class
  57. /// and optionally releases the managed resources.
  58. /// </summary>
  59. /// <param name="disposing">
  60. /// <see langword="true"/> to release both managed and unmanaged resources;
  61. /// <see langword="false"/> to release only unmanaged resources.
  62. /// </param>
  63. protected virtual void Dispose(bool disposing)
  64. {
  65. if (!_disposed)
  66. {
  67. if (disposing)
  68. {
  69. // Dispose managed resources.
  70. SetBackBuffer(null);
  71. if (_backBuffer != null)
  72. {
  73. _backBuffer.Dispose();
  74. _backBuffer = null;
  75. }
  76. }
  77. // Release unmanaged resources.
  78. UninitializeD3D9();
  79. _disposed = true;
  80. }
  81. }
  82. /// <summary>
  83. /// Initializes the Direct3D 9 device.
  84. /// </summary>
  85. private static void InitializeD3D9()
  86. {
  87. lock (_d3d9Lock)
  88. {
  89. _referenceCount++;
  90. if (_referenceCount == 1)
  91. _d3D9 = new D3D9();
  92. }
  93. }
  94. /// <summary>
  95. /// Un-initializes the Direct3D 9 device, if no longer needed.
  96. /// </summary>
  97. private static void UninitializeD3D9()
  98. {
  99. lock (_d3d9Lock)
  100. {
  101. _referenceCount--;
  102. if (_referenceCount == 0)
  103. {
  104. _d3D9.Dispose();
  105. _d3D9 = null;
  106. }
  107. }
  108. }
  109. private void ThrowIfDisposed()
  110. {
  111. if (_disposed)
  112. throw new ObjectDisposedException(GetType().FullName);
  113. }
  114. /// <summary>
  115. /// Invalidates the front buffer. (Needs to be called when the back buffer has changed.)
  116. /// </summary>
  117. public void Invalidate()
  118. {
  119. ThrowIfDisposed();
  120. if (_backBuffer != null)
  121. {
  122. Lock();
  123. AddDirtyRect(new Int32Rect(0, 0, PixelWidth, PixelHeight));
  124. Unlock();
  125. }
  126. }
  127. /// <summary>
  128. /// Sets the back buffer of the <see cref="D3D11Image"/>.
  129. /// </summary>
  130. /// <param name="texture">The Direct3D 11 texture to be used as the back buffer.</param>
  131. public void SetBackBuffer(Texture2D texture)
  132. {
  133. ThrowIfDisposed();
  134. var previousBackBuffer = _backBuffer;
  135. // Create shared texture on Direct3D 9 device.
  136. _backBuffer = _d3D9.GetSharedTexture(texture);
  137. if (_backBuffer != null)
  138. {
  139. // Set texture as new back buffer.
  140. using (Surface surface = _backBuffer.GetSurfaceLevel(0))
  141. {
  142. Lock();
  143. SetBackBuffer(D3DResourceType.IDirect3DSurface9, surface.NativePointer);
  144. Unlock();
  145. }
  146. }
  147. else
  148. {
  149. // Reset back buffer.
  150. Lock();
  151. SetBackBuffer(D3DResourceType.IDirect3DSurface9, IntPtr.Zero);
  152. Unlock();
  153. }
  154. if (previousBackBuffer != null)
  155. previousBackBuffer.Dispose();
  156. }
  157. }
  158. }