浏览代码

Direct3D interop sample

Nikita Tsukanov 8 年之前
父节点
当前提交
012451a4db

+ 43 - 0
Avalonia.sln

@@ -189,6 +189,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Linux", "Linux", "{86C53C40
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.LinuxFramebuffer", "src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj", "{854568D5-13D1-4B4F-B50D-534DC7EFD3C9}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Direct3DInteropSample", "samples\interop\Direct3DInteropSample\Direct3DInteropSample.csproj", "{638580B0-7910-40EF-B674-DCB34DA308CD}"
+EndProject
 Global
 	GlobalSection(SharedMSBuildProjectFiles) = preSolution
 		src\Skia\Avalonia.Skia\Avalonia.Skia.projitems*{2f59f3d0-748d-4652-b01e-e0d954756308}*SharedItemsImports = 13
@@ -2547,6 +2549,46 @@ Global
 		{854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Release|Mono.Build.0 = Release|Any CPU
 		{854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Release|x86.ActiveCfg = Release|Any CPU
 		{854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Release|x86.Build.0 = Release|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|Mono.ActiveCfg = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|Mono.Build.0 = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|iPhone.Build.0 = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|Mono.ActiveCfg = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|Mono.Build.0 = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|x86.ActiveCfg = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|x86.Build.0 = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|iPhone.Build.0 = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|Mono.ActiveCfg = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|Mono.Build.0 = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|x86.Build.0 = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Release|Any CPU.Build.0 = Release|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Release|iPhone.ActiveCfg = Release|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Release|iPhone.Build.0 = Release|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Release|Mono.ActiveCfg = Release|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Release|Mono.Build.0 = Release|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Release|x86.ActiveCfg = Release|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Release|x86.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -2606,5 +2648,6 @@ Global
 		{F3AC8BC1-27F5-4255-9AFC-04ABFD11683A} = {74487168-7D91-487E-BF93-055F2251461E}
 		{4D6FAF79-58B4-482F-9122-0668C346364C} = {74487168-7D91-487E-BF93-055F2251461E}
 		{854568D5-13D1-4B4F-B50D-534DC7EFD3C9} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B}
+		{638580B0-7910-40EF-B674-DCB34DA308CD} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9}
 	EndGlobalSection
 EndGlobal

+ 6 - 0
samples/interop/Direct3DInteropSample/App.paml

@@ -0,0 +1,6 @@
+<Application xmlns="https://github.com/avaloniaui">
+  <Application.Styles>
+    <StyleInclude Source="resm:Avalonia.Themes.Default.DefaultTheme.xaml?assembly=Avalonia.Themes.Default"/>
+    <StyleInclude Source="resm:Avalonia.Themes.Default.Accents.BaseLight.xaml?assembly=Avalonia.Themes.Default"/>
+  </Application.Styles>
+</Application>

+ 13 - 0
samples/interop/Direct3DInteropSample/App.paml.cs

@@ -0,0 +1,13 @@
+using Avalonia;
+using Avalonia.Markup.Xaml;
+
+namespace Direct3DInteropSample
+{
+    public class App : Application
+    {
+        public override void Initialize()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+    }
+}

+ 33 - 0
samples/interop/Direct3DInteropSample/Direct3DInteropSample.csproj

@@ -0,0 +1,33 @@
+<Project Sdk="Microsoft.NET.Sdk">
+    <PropertyGroup>
+        <OutputType>Exe</OutputType>
+        <TargetFramework>net461</TargetFramework>
+    </PropertyGroup>
+    <ItemGroup>
+        <PackageReference Include="SharpDX.Mathematics" Version="3.1.1" />
+        <PackageReference Include="SharpDX.D3DCompiler" Version="3.1.1" />
+        <Compile Update="**\*.paml.cs">
+            <DependentUpon>%(Filename)</DependentUpon>
+        </Compile>
+        <EmbeddedResource Include="**\*.paml">
+            <SubType>Designer</SubType>
+        </EmbeddedResource>
+    </ItemGroup>
+    <ItemGroup>
+      <None Remove="MiniCube.fx" />
+    </ItemGroup>
+    <ItemGroup>
+      <EmbeddedResource Include="MiniCube.fx" />
+    </ItemGroup>
+    <ItemGroup>
+        <ProjectReference Include="..\..\..\src\Avalonia.DotNetFrameworkRuntime\Avalonia.DotNetFrameworkRuntime.csproj" />
+        <ProjectReference Include="..\..\..\src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj" />
+        <ProjectReference Include="..\..\..\src\Windows\Avalonia.Direct2D1\Avalonia.Direct2D1.csproj" />
+        <ProjectReference Include="..\..\..\src\Windows\Avalonia.Win32\Avalonia.Win32.csproj" />
+    </ItemGroup>
+    <Import Project="..\..\..\build\Serilog.props" />
+    <Import Project="..\..\..\build\Serilog.Sinks.Trace.props" />
+    <Import Project="..\..\..\build\Splat.props" />
+    <Import Project="..\..\..\build\Rx.props" />
+    <Import Project="$(MSBuildThisFileDirectory)..\..\..\src\Shared\nuget.workaround.targets" />
+</Project>

+ 263 - 0
samples/interop/Direct3DInteropSample/MainWindow.cs

@@ -0,0 +1,263 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Direct2D1.Media;
+using Avalonia.Markup.Xaml;
+using Avalonia.Platform;
+using Avalonia.Rendering;
+using SharpDX;
+using SharpDX.D3DCompiler;
+using SharpDX.Direct2D1;
+using SharpDX.Direct3D;
+using SharpDX.Direct3D11;
+using SharpDX.DXGI;
+using SharpDX.WIC;
+using SharpDX.Mathematics;
+using AlphaMode = SharpDX.Direct2D1.AlphaMode;
+using Buffer = SharpDX.Direct3D11.Buffer;
+using DeviceContext = SharpDX.Direct3D11.DeviceContext;
+using Factory1 = SharpDX.DXGI.Factory1;
+using InputElement = SharpDX.Direct3D11.InputElement;
+using Matrix = SharpDX.Matrix;
+using PixelFormat = SharpDX.Direct2D1.PixelFormat;
+
+namespace Direct3DInteropSample
+{
+    class MainWindow : Window
+    {
+        private SharpDX.Direct3D11.Device _d3dDevice;
+        private SharpDX.DXGI.Device _dxgiDevice;
+        Texture2D backBuffer = null;
+        RenderTargetView renderView = null;
+        Texture2D depthBuffer = null;
+        DepthStencilView depthView = null;
+        private readonly SwapChain _swapChain;
+        private SwapChainDescription _desc;
+        private Matrix _proj = Matrix.Identity;
+        private Matrix _view;
+        private Buffer _contantBuffer;
+        private SharpDX.Direct2D1.Device _d2dDevice;
+        private SharpDX.Direct2D1.DeviceContext _d2dContext;
+        private RenderTarget _d2dRenderTarget;
+        private MainWindowViewModel _model;
+
+        public MainWindow()
+        {
+            _dxgiDevice = AvaloniaLocator.Current.GetService<SharpDX.DXGI.Device>();
+            _d3dDevice = _dxgiDevice.QueryInterface<SharpDX.Direct3D11.Device>();
+            _d2dDevice = AvaloniaLocator.Current.GetService<SharpDX.Direct2D1.Device>();
+            DataContext = _model = new MainWindowViewModel();
+            _desc = new SwapChainDescription()
+            {
+                BufferCount = 1,
+                ModeDescription =
+                   new ModeDescription((int)ClientSize.Width, (int)ClientSize.Height,
+                            new Rational(60, 1), Format.R8G8B8A8_UNorm),
+                IsWindowed = true,
+                OutputHandle = PlatformImpl.Handle.Handle,
+                SampleDescription = new SampleDescription(1, 0),
+                SwapEffect = SwapEffect.Discard,
+                Usage = Usage.RenderTargetOutput
+            };
+
+            _swapChain = new SwapChain(new Factory1(), _d3dDevice, _desc);
+
+            _d2dContext = new SharpDX.Direct2D1.DeviceContext(_d2dDevice, DeviceContextOptions.None)
+            {
+                DotsPerInch = new Size2F(96, 96)
+            };
+
+            CreateMesh();
+            _view = Matrix.LookAtLH(new Vector3(0, 0, -5), new Vector3(0, 0, 0), Vector3.UnitY);
+            this.GetObservable(ClientSizeProperty).Subscribe(Resize);
+            Resize(ClientSize);
+            AvaloniaXamlLoader.Load(this);
+        }
+
+
+        protected override void HandlePaint(Rect rect)
+        {
+            var viewProj = Matrix.Multiply(_view, _proj);
+            var context = _d3dDevice.ImmediateContext;
+            // Clear views
+            context.ClearDepthStencilView(depthView, DepthStencilClearFlags.Depth, 1.0f, 0);
+            context.ClearRenderTargetView(renderView, Color.White);
+
+            var time = 50;
+            // Update WorldViewProj Matrix
+            var worldViewProj = Matrix.RotationX((float) _model.RotationX) * Matrix.RotationY((float) _model.RotationY) *
+                                Matrix.RotationZ((float) _model.RotationZ)
+                                * Matrix.Scaling((float) _model.Zoom) * viewProj;
+            worldViewProj.Transpose();
+            context.UpdateSubresource(ref worldViewProj, _contantBuffer);
+
+            // Draw the cube
+            context.Draw(36, 0);
+            base.HandlePaint(rect);
+            // Present!
+            _swapChain.Present(0, PresentFlags.None);
+        }
+
+        
+        void CreateMesh()
+        {
+            var device = _d3dDevice;
+            // Compile Vertex and Pixel shaders
+            var vertexShaderByteCode = ShaderBytecode.CompileFromFile("MiniCube.fx", "VS", "vs_4_0");
+            var vertexShader = new VertexShader(device, vertexShaderByteCode);
+
+            var pixelShaderByteCode = ShaderBytecode.CompileFromFile("MiniCube.fx", "PS", "ps_4_0");
+            var pixelShader = new PixelShader(device, pixelShaderByteCode);
+
+            var signature = ShaderSignature.GetInputSignature(vertexShaderByteCode);
+            // Layout from VertexShader input signature
+            var layout = new InputLayout(device, signature, new[]
+                    {
+                        new InputElement("POSITION", 0, Format.R32G32B32A32_Float, 0, 0),
+                        new InputElement("COLOR", 0, Format.R32G32B32A32_Float, 16, 0)
+                    });
+            
+            // Instantiate Vertex buiffer from vertex data
+            var vertices = Buffer.Create(device, BindFlags.VertexBuffer, new[]
+                                  {
+                                      new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f), // Front
+                                      new Vector4(-1.0f,  1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
+                                      new Vector4( 1.0f,  1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
+                                      new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
+                                      new Vector4( 1.0f,  1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
+                                      new Vector4( 1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
+
+                                      new Vector4(-1.0f, -1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f), // BACK
+                                      new Vector4( 1.0f,  1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
+                                      new Vector4(-1.0f,  1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
+                                      new Vector4(-1.0f, -1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
+                                      new Vector4( 1.0f, -1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
+                                      new Vector4( 1.0f,  1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
+
+                                      new Vector4(-1.0f, 1.0f, -1.0f,  1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f), // Top
+                                      new Vector4(-1.0f, 1.0f,  1.0f,  1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
+                                      new Vector4( 1.0f, 1.0f,  1.0f,  1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
+                                      new Vector4(-1.0f, 1.0f, -1.0f,  1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
+                                      new Vector4( 1.0f, 1.0f,  1.0f,  1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
+                                      new Vector4( 1.0f, 1.0f, -1.0f,  1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
+
+                                      new Vector4(-1.0f,-1.0f, -1.0f,  1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f), // Bottom
+                                      new Vector4( 1.0f,-1.0f,  1.0f,  1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
+                                      new Vector4(-1.0f,-1.0f,  1.0f,  1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
+                                      new Vector4(-1.0f,-1.0f, -1.0f,  1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
+                                      new Vector4( 1.0f,-1.0f, -1.0f,  1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
+                                      new Vector4( 1.0f,-1.0f,  1.0f,  1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
+
+                                      new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f), // Left
+                                      new Vector4(-1.0f, -1.0f,  1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
+                                      new Vector4(-1.0f,  1.0f,  1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
+                                      new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
+                                      new Vector4(-1.0f,  1.0f,  1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
+                                      new Vector4(-1.0f,  1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
+
+                                      new Vector4( 1.0f, -1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f), // Right
+                                      new Vector4( 1.0f,  1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
+                                      new Vector4( 1.0f, -1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
+                                      new Vector4( 1.0f, -1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
+                                      new Vector4( 1.0f,  1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
+                                      new Vector4( 1.0f,  1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
+                            });
+
+            // Create Constant Buffer
+            _contantBuffer = new Buffer(device, Utilities.SizeOf<Matrix>(), ResourceUsage.Default, BindFlags.ConstantBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);
+
+            var context = _d3dDevice.ImmediateContext;
+
+            // Prepare All the stages
+            context.InputAssembler.InputLayout = layout;
+            context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
+            context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(vertices, Utilities.SizeOf<Vector4>() * 2, 0));
+            context.VertexShader.SetConstantBuffer(0, _contantBuffer);
+            context.VertexShader.Set(vertexShader);
+            context.PixelShader.Set(pixelShader);
+        }
+
+        void Resize(Size size)
+        {
+            Utilities.Dispose(ref _d2dRenderTarget);
+            Utilities.Dispose(ref backBuffer);
+            Utilities.Dispose(ref renderView);
+            Utilities.Dispose(ref depthBuffer);
+            Utilities.Dispose(ref depthView);
+            var context = _d3dDevice.ImmediateContext;
+            // Resize the backbuffer
+            _swapChain.ResizeBuffers(_desc.BufferCount, (int)size.Width, (int)size.Height, Format.Unknown, SwapChainFlags.None);
+
+            // Get the backbuffer from the swapchain
+            backBuffer = Texture2D.FromSwapChain<Texture2D>(_swapChain, 0);
+
+            // Renderview on the backbuffer
+            renderView = new RenderTargetView(_d3dDevice, backBuffer);
+
+            // Create the depth buffer
+            depthBuffer = new Texture2D(_d3dDevice, new Texture2DDescription()
+            {
+                Format = Format.D32_Float_S8X24_UInt,
+                ArraySize = 1,
+                MipLevels = 1,
+                Width = (int)size.Width,
+                Height = (int)size.Height,
+                SampleDescription = new SampleDescription(1, 0),
+                Usage = ResourceUsage.Default,
+                BindFlags = BindFlags.DepthStencil,
+                CpuAccessFlags = CpuAccessFlags.None,
+                OptionFlags = ResourceOptionFlags.None
+            });
+
+            // Create the depth buffer view
+            depthView = new DepthStencilView(_d3dDevice, depthBuffer);
+
+            // Setup targets and viewport for rendering
+            context.Rasterizer.SetViewport(new Viewport(0, 0, (int)size.Width, (int)size.Height, 0.0f, 1.0f));
+            context.OutputMerger.SetTargets(depthView, renderView);
+
+            // Setup new projection matrix with correct aspect ratio
+            _proj = Matrix.PerspectiveFovLH((float)Math.PI / 4.0f, (float)(size.Width / size.Height), 0.1f, 100.0f);
+
+            using (var dxgiBackBuffer = _swapChain.GetBackBuffer<Surface>(0))
+            {
+                _d2dRenderTarget = new RenderTarget(AvaloniaLocator.Current.GetService<SharpDX.Direct2D1.Factory>()
+                    , dxgiBackBuffer, new RenderTargetProperties
+                    {
+                        DpiX = 96,
+                        DpiY = 96,
+                        Type = RenderTargetType.Default,
+                        PixelFormat = new PixelFormat(Format.Unknown, AlphaMode.Premultiplied)
+                    });
+            }
+
+        }
+
+        class D3DRenderTarget: IRenderTarget
+        {
+            private readonly MainWindow _window;
+
+            public D3DRenderTarget(MainWindow window)
+            {
+                _window = window;
+            }
+            public void Dispose()
+            {
+                
+            }
+
+            public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer)
+            {
+                return new DrawingContextImpl(visualBrushRenderer, _window._d2dRenderTarget,
+                    AvaloniaLocator.Current.GetService<SharpDX.DirectWrite.Factory>());
+            }
+        }
+
+
+        public override IRenderTarget CreateRenderTarget() => new D3DRenderTarget(this);
+    }
+}

+ 14 - 0
samples/interop/Direct3DInteropSample/MainWindow.paml

@@ -0,0 +1,14 @@
+<Window xmlns="https://github.com/avaloniaui" Background="Transparent" Title="Avalonia Direct3D Demo">
+    <Grid ColumnDefinitions="*,Auto" Margin="20">
+        <StackPanel Grid.Column="1" MinWidth="200">
+            <TextBlock>Rotation X</TextBlock>
+            <Slider Value="{Binding RotationX, Mode=TwoWay}" Maximum="10"/>
+            <TextBlock>Rotation Y</TextBlock>
+            <Slider Value="{Binding RotationY, Mode=TwoWay}" Maximum="10"/>
+            <TextBlock>Rotation Z</TextBlock>
+            <Slider Value="{Binding RotationZ, Mode=TwoWay}" Maximum="10"/>
+            <TextBlock>Zoom</TextBlock>
+            <Slider Value="{Binding Zoom, Mode=TwoWay}" Maximum="3" Minimum="0.5"/>
+        </StackPanel>
+    </Grid>
+</Window>

+ 45 - 0
samples/interop/Direct3DInteropSample/MainWindowViewModel.cs

@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using ReactiveUI;
+
+namespace Direct3DInteropSample
+{
+    public class MainWindowViewModel : ReactiveObject
+    {
+        private double _rotationX;
+
+        public double RotationX
+        {
+            get { return _rotationX; }
+            set { this.RaiseAndSetIfChanged(ref _rotationX, value); }
+        }
+
+        private double _rotationY = 1;
+
+        public double RotationY
+        {
+            get { return _rotationY; }
+            set { this.RaiseAndSetIfChanged(ref _rotationY, value); }
+        }
+
+        private double _rotationZ = 2;
+
+        public double RotationZ
+        {
+            get { return _rotationZ; }
+            set { this.RaiseAndSetIfChanged(ref _rotationZ, value); }
+        }
+
+
+        private double _zoom = 1;
+
+        public double Zoom
+        {
+            get { return _zoom; }
+            set { this.RaiseAndSetIfChanged(ref _zoom, value); }
+        }
+    }
+}

+ 47 - 0
samples/interop/Direct3DInteropSample/MiniCube.fx

@@ -0,0 +1,47 @@
+// Copyright (c) 2010-2013 SharpDX - Alexandre Mutel
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+struct VS_IN
+{
+	float4 pos : POSITION;
+	float4 col : COLOR;
+};
+
+struct PS_IN
+{
+	float4 pos : SV_POSITION;
+	float4 col : COLOR;
+};
+
+float4x4 worldViewProj;
+
+PS_IN VS( VS_IN input )
+{
+	PS_IN output = (PS_IN)0;
+	
+	output.pos = mul(input.pos, worldViewProj);
+	output.col = input.col;
+	
+	return output;
+}
+
+float4 PS( PS_IN input ) : SV_Target
+{
+	return input.col;
+}

+ 17 - 0
samples/interop/Direct3DInteropSample/Program.cs

@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Avalonia;
+
+namespace Direct3DInteropSample
+{
+    class Program
+    {
+        static void Main(string[] args)
+        {
+            AppBuilder.Configure<App>().UseWin32().UseDirect2D1().Start<MainWindow>();
+        }
+    }
+}

+ 1 - 1
src/Avalonia.Controls/TopLevel.cs

@@ -185,7 +185,7 @@ namespace Avalonia.Controls
         }
 
         /// <inheritdoc/>
-        IRenderTarget IRenderRoot.CreateRenderTarget()
+        public virtual IRenderTarget CreateRenderTarget()
         {
             return _renderInterface.CreateRenderTarget(PlatformImpl.Surfaces);
         }