Advertisement
kkc0923

SurfaceImageSource

Nov 25th, 2012
688
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 9.26 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using SharpDX;
  7. using SharpDX.DXGI;
  8. using Windows.Foundation;
  9. using Windows.UI.Xaml.Media.Imaging;
  10.  
  11. namespace NovelReader.DirectX
  12. {
  13.     /// <summary>
  14.     /// Target to render to a <see cref="SurfaceImageSource"/>, used to integrate
  15.     /// DirectX content into a XAML brush.
  16.     /// </summary>
  17.     public class SurfaceImageSourceTarget : TargetBase
  18.     {
  19.         private Dictionary<IntPtr, SurfaceViewData> mapSurfaces = new Dictionary<IntPtr, SurfaceViewData>();
  20.  
  21.         private int pixelWidth;
  22.         private int pixelHeight;
  23.         private SurfaceImageSource surfaceImageSource;
  24.         private ISurfaceImageSourceNative surfaceImageSourceNative;
  25.         private readonly SurfaceViewData[] viewDatas = new SurfaceViewData[2];
  26.         private DrawingPoint position;
  27.         private int nextViewDataIndex;
  28.  
  29.  
  30.         /// <summary>
  31.         /// Initialzes a new <see cref="SurfaceImageSourceTarget"/> instance.
  32.         /// </summary>
  33.         /// <param name="pixelWidth">Width of the target in pixels</param>
  34.         /// <param name="pixelHeight">Height of the target in pixels</param>
  35.         public SurfaceImageSourceTarget(int pixelWidth, int pixelHeight, bool supportOpacity = false)
  36.         {
  37.             this.pixelWidth = pixelWidth;
  38.             this.pixelHeight = pixelHeight;
  39.             this.surfaceImageSource = new SurfaceImageSource(pixelWidth, pixelHeight, supportOpacity);
  40.             surfaceImageSourceNative = ToDispose(ComObject.As<SharpDX.DXGI.ISurfaceImageSourceNative>(surfaceImageSource));
  41.             viewDatas[0] = new SurfaceViewData();
  42.             viewDatas[1] = new SurfaceViewData();
  43.  
  44.  
  45.         }
  46.  
  47.         /// <summary>
  48.         /// Gets the <see cref="SurfaceImageSource"/> to be used by brushes.
  49.         /// </summary>
  50.         public SurfaceImageSource ImageSource
  51.         {
  52.             get
  53.             {
  54.                 return surfaceImageSource;
  55.             }
  56.         }
  57.  
  58.         /// <inveritdoc/>
  59.         public override void Initialize(DeviceManager deviceManager)
  60.         {
  61.             base.Initialize(deviceManager);
  62.             surfaceImageSourceNative.Device = ToDispose(DeviceManager.DeviceDirect3D.QueryInterface<SharpDX.DXGI.Device>());
  63.  
  64.         }
  65.  
  66.         /// <inveritdoc/>
  67.         protected override Windows.Foundation.Rect CurrentControlBounds
  68.         {
  69.             get
  70.             {
  71.                 return new Windows.Foundation.Rect(0, 0, pixelWidth, pixelHeight);
  72.             }
  73.         }
  74.  
  75.         /// <summary>
  76.         /// Gets the relative position to use to draw on the surface.
  77.         /// </summary>
  78.         public DrawingPoint DrawingPosition { get { return position; } }
  79.  
  80.         /// <inveritdoc/>
  81.         public override void RenderAll()
  82.         {
  83.             SurfaceViewData viewData = null;
  84.  
  85.             var regionToDraw = new SharpDX.Rectangle(0, 0, pixelWidth, pixelHeight);
  86.  
  87.             // Unlike other targets, we can only get the DXGI surface to render to
  88.             // just before rendering.
  89.             using (var surface = surfaceImageSourceNative.BeginDraw(regionToDraw, out position))
  90.             {
  91.                 // Cache DXGI surface in order to avoid recreate all render target view, depth stencil...etc.
  92.                 // Is it the right way to do it?
  93.                 // It seems that ISurfaceImageSourceNative.BeginDraw is returning 2 different DXGI surfaces (when the application is in foreground)
  94.                 // or different DXGI surfaces (when the application is in background).
  95.                 foreach (var surfaceViewData in viewDatas)
  96.                 {
  97.                     if (surfaceViewData.SurfacePointer == surface.NativePointer)
  98.                     {
  99.                         viewData = surfaceViewData;
  100.                         break;
  101.                     }
  102.                 }
  103.  
  104.                 if (viewData == null)
  105.                 {
  106.                     viewData = viewDatas[nextViewDataIndex];
  107.                     nextViewDataIndex = (nextViewDataIndex + 1) % viewDatas.Length;
  108.  
  109.                     // Make sure that previous was disposed.
  110.                     viewData.Dispose();
  111.                     viewData.SurfacePointer = surface.NativePointer;
  112.  
  113.                     // Allocate a new renderTargetView if size is different
  114.                     // Cache the rendertarget dimensions in our helper class for convenient use.
  115.                     viewData.BackBuffer = surface.QueryInterface<SharpDX.Direct3D11.Texture2D>();
  116.                     {
  117.                         var desc = viewData.BackBuffer.Description;
  118.                         desc.SampleDescription = new SampleDescription(1, 0);
  119.                         viewData.RenderTargetSize = new Size(desc.Width, desc.Height);
  120.                         viewData.RenderTargetView = new SharpDX.Direct3D11.RenderTargetView(DeviceManager.DeviceDirect3D, viewData.BackBuffer);
  121.                     }
  122.  
  123.                    
  124.                     // Create a descriptor for the depth/stencil buffer.
  125.                     // Allocate a 2-D surface as the depth/stencil buffer.
  126.                     // Create a DepthStencil view on this surface to use on bind.
  127.                     // TODO: Recreate a DepthStencilBuffer is inefficient. We should only have one depth buffer. Shared depth buffer?
  128.                     using (var depthBuffer = new SharpDX.Direct3D11.Texture2D(DeviceManager.DeviceDirect3D, new SharpDX.Direct3D11.Texture2DDescription()
  129.                     {
  130.                         Format = SharpDX.DXGI.Format.D24_UNorm_S8_UInt,
  131.                         ArraySize = 1,
  132.                         MipLevels = 0,
  133.                         Width = (int)viewData.RenderTargetSize.Width,
  134.                         Height = (int)viewData.RenderTargetSize.Height,
  135.                         SampleDescription = new SharpDX.DXGI.SampleDescription(1, 0),
  136.                         BindFlags = SharpDX.Direct3D11.BindFlags.DepthStencil,
  137.                     }))
  138.                         viewData.DepthStencilView = new SharpDX.Direct3D11.DepthStencilView(DeviceManager.DeviceDirect3D, depthBuffer, new SharpDX.Direct3D11.DepthStencilViewDescription() { Dimension = SharpDX.Direct3D11.DepthStencilViewDimension.Texture2D });
  139.  
  140.                     // Now we set up the Direct2D render target bitmap linked to the swapchain.
  141.                     // Whenever we render to this bitmap, it will be directly rendered to the
  142.                     // swapchain associated with the window.
  143.                     var bitmapProperties = new SharpDX.Direct2D1.BitmapProperties1(
  144.                         new SharpDX.Direct2D1.PixelFormat(SharpDX.DXGI.Format.B8G8R8A8_UNorm, SharpDX.Direct2D1.AlphaMode.Premultiplied),
  145.                         DeviceManager.Dpi,
  146.                         DeviceManager.Dpi,
  147.                         SharpDX.Direct2D1.BitmapOptions.Target | SharpDX.Direct2D1.BitmapOptions.CannotDraw);
  148.  
  149.                     // Direct2D needs the dxgi version of the backbuffer surface pointer.
  150.                     // Get a D2D surface from the DXGI back buffer to use as the D2D render target.
  151.                     viewData.BitmapTarget = new SharpDX.Direct2D1.Bitmap1(DeviceManager.ContextDirect2D, surface, bitmapProperties);
  152.  
  153.                     // Create a viewport descriptor of the full window size.
  154.                     viewData.Viewport = new SharpDX.Direct3D11.Viewport(position.X, position.Y, (float)viewData.RenderTargetSize.Width - position.X, (float)viewData.RenderTargetSize.Height - position.Y, 0.0f, 1.0f);
  155.                 }
  156.  
  157.                 backBuffer = viewData.BackBuffer;
  158.                 renderTargetView = viewData.RenderTargetView;
  159.                 depthStencilView = viewData.DepthStencilView;
  160.                 RenderTargetBounds = new Rect(viewData.Viewport.TopLeftX, viewData.Viewport.TopLeftY, viewData.Viewport.Width, viewData.Viewport.Height);
  161.                 bitmapTarget = viewData.BitmapTarget;
  162.  
  163.                 DeviceManager.ContextDirect2D.Target = viewData.BitmapTarget;
  164.  
  165.                 // Set the current viewport using the descriptor.
  166.                 DeviceManager.ContextDirect3D.Rasterizer.SetViewports(viewData.Viewport);
  167.  
  168.                 // Perform the actual rendering of this target
  169.                 base.RenderAll();
  170.             }
  171.  
  172.             surfaceImageSourceNative.EndDraw();
  173.         }
  174.  
  175.         /// <summary>
  176.         /// This class is used to store attached render target view to DXGI surfaces.
  177.         /// </summary>
  178.         class SurfaceViewData : IDisposable
  179.         {
  180.             public IntPtr SurfacePointer;
  181.             public SharpDX.Direct3D11.Texture2D BackBuffer;
  182.             public SharpDX.Direct3D11.RenderTargetView RenderTargetView;
  183.             public SharpDX.Direct3D11.DepthStencilView DepthStencilView;
  184.             public SharpDX.Direct2D1.Bitmap1 BitmapTarget;
  185.             public SharpDX.Direct3D11.Viewport Viewport;
  186.             public Size RenderTargetSize;
  187.  
  188.             public void Dispose()
  189.             {
  190.                 ComObject.Dispose(ref BitmapTarget);
  191.                 ComObject.Dispose(ref RenderTargetView);
  192.                 ComObject.Dispose(ref DepthStencilView);
  193.                 ComObject.Dispose(ref BackBuffer);
  194.                 SurfacePointer = IntPtr.Zero;
  195.             }
  196.         }
  197.     }
  198. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement