using System; using System.Windows; using System.Windows.Interop; using Microsoft.Xna.Framework.Graphics; using SharpDX.Direct3D9; using Texture = SharpDX.Direct3D9.Texture; namespace WpfInteropSample { /// /// Wraps the to make it compatible with Direct3D 11. /// /// /// The should be disposed if no longer needed! /// internal class D3D11Image : D3DImage, IDisposable { // Use a Direct3D 9 device for interoperability. The device is shared by // all D3D11Images. private static D3D9 _d3D9; private static int _referenceCount; private static readonly object _d3d9Lock = new object(); private bool _disposed; private Texture _backBuffer; /// /// Initializes a new instance of the class. /// public D3D11Image() { InitializeD3D9(); } /// /// Releases unmanaged resources before an instance of the class is /// reclaimed by garbage collection. /// /// /// This method releases unmanaged resources by calling the virtual /// method, passing in . /// ~D3D11Image() { Dispose(false); } /// /// Releases all resources used by an instance of the class. /// /// /// This method calls the virtual method, passing in /// , and then suppresses finalization of the instance. /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// /// Releases the unmanaged resources used by an instance of the class /// and optionally releases the managed resources. /// /// /// to release both managed and unmanaged resources; /// to release only unmanaged resources. /// protected virtual void Dispose(bool disposing) { if (!_disposed) { if (disposing) { // Dispose managed resources. SetBackBuffer(null); if (_backBuffer != null) { _backBuffer.Dispose(); _backBuffer = null; } } // Release unmanaged resources. UninitializeD3D9(); _disposed = true; } } /// /// Initializes the Direct3D 9 device. /// private static void InitializeD3D9() { lock (_d3d9Lock) { _referenceCount++; if (_referenceCount == 1) _d3D9 = new D3D9(); } } /// /// Un-initializes the Direct3D 9 device, if no longer needed. /// private static void UninitializeD3D9() { lock (_d3d9Lock) { _referenceCount--; if (_referenceCount == 0) { _d3D9.Dispose(); _d3D9 = null; } } } private void ThrowIfDisposed() { if (_disposed) throw new ObjectDisposedException(GetType().FullName); } /// /// Invalidates the front buffer. (Needs to be called when the back buffer has changed.) /// public void Invalidate() { ThrowIfDisposed(); if (_backBuffer != null) { Lock(); AddDirtyRect(new Int32Rect(0, 0, PixelWidth, PixelHeight)); Unlock(); } } /// /// Sets the back buffer of the . /// /// The Direct3D 11 texture to be used as the back buffer. public void SetBackBuffer(Texture2D texture) { ThrowIfDisposed(); var previousBackBuffer = _backBuffer; // Create shared texture on Direct3D 9 device. _backBuffer = _d3D9.GetSharedTexture(texture); if (_backBuffer != null) { // Set texture as new back buffer. using (Surface surface = _backBuffer.GetSurfaceLevel(0)) { Lock(); SetBackBuffer(D3DResourceType.IDirect3DSurface9, surface.NativePointer); Unlock(); } } else { // Reset back buffer. Lock(); SetBackBuffer(D3DResourceType.IDirect3DSurface9, IntPtr.Zero); Unlock(); } if (previousBackBuffer != null) previousBackBuffer.Dispose(); } } }