SurfaceImageSource Manager is a C++ WinRT component making it easy to produce ready-to-use SurfaceImageSource instances, and then use DirectX or Direct2D to define their aspect in C# Metro applications.

Please Sign up or sign in to vote.

SurfaceImageSource Manager: Connecting C# and DirectX/Direct2D using the WinRT/Metro SurfaceImageSource class, through a small C++ component

Introduction

WinRT includes a SurfaceImageSource class deriving from ImageSource making it easy to inject DirectX or Direct2D drawings in a Metro visual tree, as described in this article: "Combining XAML and DirectX". SurfaceImageSource is fully available to C++, but not to C#.

Background

The project requires the Windows 8 Customer Preview, the VS.NET 2011 Beta, and the SharpDX for Win8 Preview assemblies. The "Combining XAML and DirectX" article is a recommended reading.

Using the code

The SurfaceImageSource Manager solution provides the code for a KSurfaceImageSourceManager WinRT C++ Component along with a Test_SurfaceImageSourceManager C# Metro application showing how to use it. Test_SurfaceImageSourceManager relies on DXSharp to exploit the DirectX and Direct2D objects produced and returned by the KSurfaceImageSourceManager component.

Describing the KSurfaceImageSourceManager WinRT C++ Component

The role of the KSurfaceImageSourceManager component is to:

produce ready-to-use, fully connected, instances of the SurfaceImageSource WinRT class, given a ( pixelWidth , pixelHeight ) size ( NewSurfaceImageSource ), and later unregister the instance ( DeleteSurfaceImageSource ).

WinRT class, given a ( , ) size ( ), and later unregister the instance ( ). initialize and terminate Direct2D drawing sessions on a given SurfaceImageSource ( BeginDraw2D / EndDraw2D ).

( / ). initialize and terminate DirectX drawing sessions on a given SurfaceImageSource ( BeginDraw3D / EndDraw3D ).

( / ). provide the handles to the various Direct2D/DirectX devices, context handles owned by a given KSurfaceImageSourceManager ( Get_ID3D11Device , Get_ID3D11DeviceContext , ...).

The public signature of the KSurfaceImageSourceManager class looks like:

public ref class KSurfaceImageSourceManager sealed { public : KSurfaceImageSourceManager(); int Get_ID3D11Device(); int Get_ID3D11DeviceContext(); int Get_IDXGIDevice(); int Get_ID2D1Factory1(); int Get_ID2D1Device(); int Get_ID2D1DeviceContext(); SurfaceImageSource^ NewSurfaceImageSource( int pixelWidth, int pixelHeight); void DeleteSurfaceImageSource(SurfaceImageSource^ pSurfaceImageSource); int GetSurfaceImageSourceSize(SurfaceImageSource^ pSurfaceImageSource, int * pWidth, int * pHeight); int ClearSurfaceImageSource(SurfaceImageSource^ pSurfaceImageSource, float R, float G, float B, float A); int BeginDraw2D(SurfaceImageSource^ pSurfaceImageSource, int * pOffsetX, int * pOffsetY, int * pSurfaceWidth, int * pSurfaceHeight); void EndDraw2D(SurfaceImageSource^ pSurfaceImageSource); int BeginDraw3D(SurfaceImageSource^ pSurfaceImageSource, int * pOffsetX, int * pOffsetY, int * pSurfaceWidth, int * pSurfaceHeight); void EndDraw3D(SurfaceImageSource^ pSurfaceImageSource); }; };

A SurfaceImageSource produced by a KSurfaceImageSourceManager can be connected to an Image component as its Source ( Image.Source property).

KSurfaceImageSourceManager _pKSurfaceImageSourceManager = new KSurfaceImageSourceManager(); SurfaceImageSource _pSurfaceImageSource = _pKSurfaceImageSourceManager.NewSurfaceImageSource( 512 , 512 ); im2D.Source = _pSurfaceImageSource;

Using KSurfaceImageSourceManager to manage Direct2D drawing sessions targeting a SurfaceImageSource

KSurfaceImageSourceManager makes it possible to perform Direct2D drawing sessions, opened by a call to BeginDraw2D and later closed by a call to EndDraw2D , on a SurfaceImageSource .

Each call to the KSurfaceImageSourceManager BeginDraw2D method returns a handle used to produce an instance of the SharpDX.Direct2D1.RenderTarget class and perform any Direct2D painting operation targeting the DXGI surface owned by a given SurfaceImageSource , as illustrated below:

{ int _hrenderTarget = 0 ; int _offsetx = 0 ; int _offsety = 0 ; int _surfacewidth = 0 ; int _surfaceheight = 0 ; try { _hrenderTarget = _pKSurfaceImageSourceManager.BeginDraw2D(_pSurfaceImageSource, out _offsetx, out _offsety, out _surfacewidth, out _surfaceheight); RenderTarget _pRenderTarget = new RenderTarget( new IntPtr (_hrenderTarget)); { _pRenderTarget.BeginDraw(); SharpDX.Direct2D1.SolidColorBrush _brush = null ; int _left = _offsetx; int _top = _offsety; int _right = _surfacewidth; int _bottom = _surfaceheight; _brush = new SharpDX.Direct2D1.SolidColorBrush(_pRenderTarget, new SharpDX.Color4( 1 , 0 , 0 , 1 )); _pRenderTarget.FillRectangle( new SharpDX.RectangleF(_left, _top, _right, _bottom), _brush); int _border = 2 ; float _shade = 0 .25f; _brush = new SharpDX.Direct2D1.SolidColorBrush(_pRenderTarget, new SharpDX.Color4(_shade, _shade, _shade, 1 )); _pRenderTarget.FillRectangle( new SharpDX.RectangleF(_left + _border, _top + _border, _right - 2 * _border, _bottom - 2 * _border), _brush); _pRenderTarget.EndDraw(); } } catch (Exception E) { } finally { _pKSurfaceImageSourceManager.EndDraw2D(_pSurfaceImageSource); } }

Using KSurfaceImageSourceManager to manage DirectX11 drawing sessions targeting a SurfaceImageSource

The KSurfaceImageSourceManager class exposes a Get_ID3D11Device method which returns a handle to be used to create a wrapping instance of the SharpDX.Direct3D11.Device1 class.

KSurfaceImageSourceManager makes possible to perform DirectX11 drawing sessions, opened by a call to BeginDraw3D and later closed by a call to EndDraw3D on a SurfaceImageSource .

Each call to the KSurfaceImageSourceManager BeginDraw3D method returns a handle used to produce an instance of the SharpDX.Direct3D11.Texture2D wrapping class, as illustrated in the code below:

{ int _hdevice = 0 ; int _pID3D11Texture2D = 0 ; int _offsetx = 0 ; int _offsety = 0 ; int _surfacewidth = 0 ; int _surfaceheight = 0 ; try { _hdevice = _pKSurfaceImageSourceManager.Get_ID3D11Device(); SharpDX.Direct3D11.Device1 _device = new SharpDX.Direct3D11.Device1( new IntPtr (_hdevice)); _pID3D11Texture2D = _pKSurfaceImageSourceManager.BeginDraw3D(_pSurfaceImageSource, out _offsetx, out _offsety, out _surfacewidth, out _surfaceheight); Texture2D _pTexture2D = new Texture2D( new IntPtr (_pID3D11Texture2D)); SharpDX.Direct3D11.DeviceContext _context = _device.ImmediateContext; var _renderView = new RenderTargetView(_device, _pTexture2D); _context.OutputMerger.SetTargets(_renderView); _context.ClearRenderTargetView(_renderView, new Color4( 0 , 0 , 1 , 1f)); { int _x = _offsetx; int _y = _offsety; int _dx = (_surfacewidth - _offsetx); int _dy = (_surfaceheight - _offsety); _context.Rasterizer.SetViewports( new Viewport(_x, _y, _dx, _dy, 0 .0f, 1 .0f)); } render(_device, _context); } catch (Exception E) { } finally { _pKSurfaceImageSourceManager.EndDraw3D(_pSurfaceImageSource); } }

Extra goodies

The Test_SurfaceImageSourceManager project C# source code provides a few extra goodies: