diff --git a/build/SharpDX.props b/build/SharpDX.props
index e381bc03e6..0eb910e71e 100644
--- a/build/SharpDX.props
+++ b/build/SharpDX.props
@@ -3,6 +3,7 @@
+
diff --git a/samples/interop/WindowsInteropTest/Program.cs b/samples/interop/WindowsInteropTest/Program.cs
index 4770688ecf..fac06d74b0 100644
--- a/samples/interop/WindowsInteropTest/Program.cs
+++ b/samples/interop/WindowsInteropTest/Program.cs
@@ -15,7 +15,7 @@ namespace WindowsInteropTest
{
System.Windows.Forms.Application.EnableVisualStyles();
System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false);
- AppBuilder.Configure().UseWin32().UseSkia().SetupWithoutStarting();
+ AppBuilder.Configure().UseWin32().UseDirect2D1().SetupWithoutStarting();
System.Windows.Forms.Application.Run(new SelectorForm());
}
}
diff --git a/src/Windows/Avalonia.Direct2D1/ExternalRenderTarget.cs b/src/Windows/Avalonia.Direct2D1/ExternalRenderTarget.cs
index b1c0e7e30a..307048f7b4 100644
--- a/src/Windows/Avalonia.Direct2D1/ExternalRenderTarget.cs
+++ b/src/Windows/Avalonia.Direct2D1/ExternalRenderTarget.cs
@@ -15,7 +15,6 @@ namespace Avalonia.Direct2D1
{
private readonly IExternalDirect2DRenderTargetSurface _externalRenderTargetProvider;
private readonly DirectWriteFactory _dwFactory;
- private SharpDX.Direct2D1.RenderTarget _target;
public ExternalRenderTarget(IExternalDirect2DRenderTargetSurface externalRenderTargetProvider,
DirectWriteFactory dwFactory)
{
@@ -25,15 +24,14 @@ namespace Avalonia.Direct2D1
public void Dispose()
{
- _target?.Dispose();
- _target = null;
+ _externalRenderTargetProvider.DestroyRenderTarget();
}
public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer)
{
- _target = _target ?? _externalRenderTargetProvider.CreateRenderTarget();
+ var target = _externalRenderTargetProvider.GetOrCreateRenderTarget();
_externalRenderTargetProvider.BeforeDrawing();
- return new DrawingContextImpl(visualBrushRenderer, _target, _dwFactory, null, () =>
+ return new DrawingContextImpl(visualBrushRenderer, target, _dwFactory, null, () =>
{
try
{
@@ -41,8 +39,7 @@ namespace Avalonia.Direct2D1
}
catch (SharpDXException ex) when ((uint) ex.HResult == 0x8899000C) // D2DERR_RECREATE_TARGET
{
- _target?.Dispose();
- _target = null;
+ _externalRenderTargetProvider.DestroyRenderTarget();
}
});
}
diff --git a/src/Windows/Avalonia.Direct2D1/IExternalDirect2DRenderTargetSurface.cs b/src/Windows/Avalonia.Direct2D1/IExternalDirect2DRenderTargetSurface.cs
index 0774c25937..aad51f46d5 100644
--- a/src/Windows/Avalonia.Direct2D1/IExternalDirect2DRenderTargetSurface.cs
+++ b/src/Windows/Avalonia.Direct2D1/IExternalDirect2DRenderTargetSurface.cs
@@ -8,7 +8,8 @@ namespace Avalonia.Direct2D1
{
public interface IExternalDirect2DRenderTargetSurface
{
- SharpDX.Direct2D1.RenderTarget CreateRenderTarget();
+ SharpDX.Direct2D1.RenderTarget GetOrCreateRenderTarget();
+ void DestroyRenderTarget();
void BeforeDrawing();
void AfterDrawing();
}
diff --git a/src/Windows/Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj b/src/Windows/Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj
index c5cd2ab64d..099a7f4074 100644
--- a/src/Windows/Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj
+++ b/src/Windows/Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj
@@ -49,6 +49,7 @@
+
@@ -104,10 +105,18 @@
{6417e941-21bc-467b-a771-0de389353ce6}
Avalonia.Markup
+
+ {3e908f67-5543-4879-a1dc-08eace79b3cd}
+ Avalonia.Direct2D1
+
{811a76cf-1cf6-440f-963b-bbe31bd72a82}
Avalonia.Win32
+
+ true
+
+
\ No newline at end of file
diff --git a/src/Windows/Avalonia.Win32.Interop/Wpf/Direct2DImageSurface.cs b/src/Windows/Avalonia.Win32.Interop/Wpf/Direct2DImageSurface.cs
new file mode 100644
index 0000000000..303e0850aa
--- /dev/null
+++ b/src/Windows/Avalonia.Win32.Interop/Wpf/Direct2DImageSurface.cs
@@ -0,0 +1,206 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Interop;
+using Avalonia.Direct2D1;
+using SharpDX;
+using SharpDX.Direct2D1;
+using SharpDX.Direct3D11;
+using SharpDX.Direct3D9;
+using SharpDX.DXGI;
+using AlphaMode = SharpDX.Direct2D1.AlphaMode;
+using Device = SharpDX.Direct3D11.Device;
+using Format = SharpDX.DXGI.Format;
+using MapFlags = SharpDX.Direct3D11.MapFlags;
+using PresentParameters = SharpDX.DXGI.PresentParameters;
+using RenderTarget = SharpDX.Direct2D1.RenderTarget;
+using Surface = SharpDX.DXGI.Surface;
+using SwapEffect = SharpDX.DXGI.SwapEffect;
+using Usage = SharpDX.Direct3D9.Usage;
+
+namespace Avalonia.Win32.Interop.Wpf
+{
+ class Direct2DImageSurface : IExternalDirect2DRenderTargetSurface
+ {
+ class Pair: IDisposable
+ {
+ public SharpDX.Direct3D9.Surface Texture { get; }
+ public SharpDX.Direct3D11.Resource D3D11Resource { get; }
+ public SharpDX.Direct3D11.Resource StagingResource { get; }
+ public RenderTarget Target { get;}
+ public Size Size { get; }
+
+ public Pair(Size size, Vector dpi)
+ {
+ int width = (int) size.Width;
+ int height = (int) size.Height;
+ using (var texture = new Texture2D(s_dxDevice, new Texture2DDescription
+ {
+ Width = width,
+ Height = height,
+ ArraySize = 1,
+ MipLevels = 1,
+ Format = Format.B8G8R8A8_UNorm,
+ Usage = ResourceUsage.Default,
+ SampleDescription = new SampleDescription(1, 0),
+ BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource,
+ OptionFlags = ResourceOptionFlags.Shared
+ }))
+ using (var surface = texture.QueryInterface())
+ using (var resource = texture.QueryInterface())
+ {
+ D3D11Resource = texture.QueryInterface();
+ var handle = resource.SharedHandle;
+ using (var texture9 = new Texture(s_d3DDevice, texture.Description.Width,
+ texture.Description.Height, 1,
+ Usage.RenderTarget, SharpDX.Direct3D9.Format.A8R8G8B8, Pool.Default, ref handle))
+ Texture = texture9.GetSurfaceLevel(0);
+ Target = new RenderTarget(AvaloniaLocator.Current.GetService(), surface,
+ new RenderTargetProperties
+ {
+ DpiX = (float) dpi.X,
+ DpiY = (float) dpi.Y,
+ MinLevel = FeatureLevel.Level_10,
+ PixelFormat = new PixelFormat(Format.B8G8R8A8_UNorm, AlphaMode.Premultiplied),
+
+ });
+ }
+ using (var texture = new Texture2D(s_dxDevice, new Texture2DDescription
+ {
+ Width = Math.Min(width, 16),
+ Height = Math.Min(height, 16),
+ ArraySize = 1,
+ MipLevels = 1,
+ Format = Format.B8G8R8A8_UNorm,
+ Usage = ResourceUsage.Staging,
+ SampleDescription = new SampleDescription(1, 0),
+ CpuAccessFlags = CpuAccessFlags.Read
+ }))
+ StagingResource = texture.QueryInterface();
+ Size = size;
+ }
+
+ public void Dispose()
+ {
+ Texture?.Dispose();
+ Target?.Dispose();
+ D3D11Resource?.Dispose();
+ StagingResource?.Dispose();
+ }
+
+ public void Flush()
+ {
+
+ s_dxDevice.ImmediateContext.CopySubresourceRegion(D3D11Resource, 0,
+ new ResourceRegion(0, 0, 0, 1, 1, 1), StagingResource, 0, 0, 0, 0);
+ s_dxDevice.ImmediateContext.MapSubresource(StagingResource, 0, MapMode.Read, MapFlags.None);
+ s_dxDevice.ImmediateContext.UnmapSubresource(StagingResource, 0);
+
+ }
+ }
+
+ private D3DImage _image;
+ private Pair _backBuffer;
+ private Pair _frontBuffer;
+ private readonly WpfTopLevelImpl _impl;
+ private static Device s_dxDevice;
+ private static Direct3DEx s_d3DContext;
+ private static DeviceEx s_d3DDevice;
+
+
+ [DllImport("user32.dll", SetLastError = false)]
+ private static extern IntPtr GetDesktopWindow();
+ void EnsureDirectX()
+ {
+ if(s_d3DDevice != null)
+ return;
+ s_d3DContext = new Direct3DEx();
+
+ SharpDX.Direct3D9.PresentParameters presentparams = new SharpDX.Direct3D9.PresentParameters
+ {
+ Windowed = true,
+ SwapEffect = SharpDX.Direct3D9.SwapEffect.Discard,
+ DeviceWindowHandle = GetDesktopWindow(),
+ PresentationInterval = PresentInterval.Default
+ };
+ s_dxDevice = s_dxDevice ?? AvaloniaLocator.Current.GetService()
+ .QueryInterface();
+ s_d3DDevice = new DeviceEx(s_d3DContext, 0, DeviceType.Hardware, IntPtr.Zero, CreateFlags.HardwareVertexProcessing | CreateFlags.Multithreaded | CreateFlags.FpuPreserve, presentparams);
+
+ }
+
+ public Direct2DImageSurface(WpfTopLevelImpl impl)
+ {
+ _impl = impl;
+ }
+
+ public RenderTarget GetOrCreateRenderTarget()
+ {
+ EnsureDirectX();
+ var scale = _impl.GetScaling();
+ var size = new Size(_impl.ActualWidth * scale.X, _impl.ActualHeight * scale.Y);
+ var dpi = scale * 96;
+
+ if (_backBuffer!=null && _backBuffer.Size == size)
+ return _backBuffer.Target;
+
+ if (_image == null)
+ _image = new DX11Image();
+ _impl.ImageSource = _image;
+
+
+
+ RemoveAndDispose(ref _backBuffer);
+ if (size == default(Size))
+ {
+ RemoveAndDispose(ref _frontBuffer);
+ _image.Lock();
+ _image.SetBackBuffer(D3DResourceType.IDirect3DSurface9, IntPtr.Zero);
+ _image.Unlock();
+ return null;
+ }
+ _backBuffer = new Pair(size, dpi);
+
+ return _backBuffer.Target;
+ }
+
+ void RemoveAndDispose(ref T d) where T : IDisposable
+ {
+ d?.Dispose();
+ d = default(T);
+ }
+
+ void DoSwap()
+ {
+
+ }
+
+ void Swap()
+ {
+ var oldFront = _frontBuffer;
+ _frontBuffer = _backBuffer;
+ _backBuffer = oldFront;
+ _frontBuffer.Flush();
+ _image.Lock();
+ _image.SetBackBuffer(D3DResourceType.IDirect3DSurface9, _frontBuffer?.Texture?.NativePointer ?? IntPtr.Zero, true);
+ _image.AddDirtyRect(new Int32Rect(0, 0, _image.PixelWidth, _image.PixelHeight));
+ _image.Unlock();
+ }
+
+ public void DestroyRenderTarget()
+ {
+ //?
+ }
+
+ public void BeforeDrawing()
+ {
+
+ }
+
+ public void AfterDrawing() => Swap();
+ }
+}
diff --git a/src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs b/src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs
index 0620c6cc57..b5715d43d5 100644
--- a/src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs
+++ b/src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs
@@ -60,7 +60,7 @@ namespace Avalonia.Win32.Interop.Wpf
PresentationSource.AddSourceChangedHandler(this, OnSourceChanged);
_hook = WndProc;
_ttl = this;
- _surfaces = new object[] {new WritableBitmapSurface(this)};
+ _surfaces = new object[] {new WritableBitmapSurface(this), new Direct2DImageSurface(this)};
_mouse = new WpfMouseDevice(this);
_keyboard = AvaloniaLocator.Current.GetService();
@@ -224,6 +224,13 @@ namespace Avalonia.Win32.Interop.Wpf
Action ITopLevelImpl.ScalingChanged { get; set; }
Action ITopLevelImpl.Closed { get; set; }
public new event Action LostFocus;
-
+
+ internal Vector GetScaling()
+ {
+ var src = PresentationSource.FromVisual(this)?.CompositionTarget;
+ if (src == null)
+ return new Vector(1, 1);
+ return new Vector(src.TransformToDevice.M11, src.TransformToDevice.M22);
+ }
}
}
diff --git a/src/Windows/Avalonia.Win32.Interop/Wpf/WritableBitmapSurface.cs b/src/Windows/Avalonia.Win32.Interop/Wpf/WritableBitmapSurface.cs
index 1dd1cb983a..0f8752fb8d 100644
--- a/src/Windows/Avalonia.Win32.Interop/Wpf/WritableBitmapSurface.cs
+++ b/src/Windows/Avalonia.Win32.Interop/Wpf/WritableBitmapSurface.cs
@@ -24,7 +24,7 @@ namespace Avalonia.Win32.Interop.Wpf
public ILockedFramebuffer Lock()
{
- var scale = GetScaling();
+ var scale = _impl.GetScaling();
var size = new Size(_impl.ActualWidth * scale.X, _impl.ActualHeight * scale.Y);
var dpi = scale * 96;
if (_bitmap == null || _bitmap.PixelWidth != (int) size.Width || _bitmap.PixelHeight != (int) size.Height)
@@ -69,13 +69,5 @@ namespace Avalonia.Win32.Interop.Wpf
public Vector Dpi { get; }
public PixelFormat Format => PixelFormat.Bgra8888;
}
-
- Vector GetScaling()
- {
- var src = PresentationSource.FromVisual(_impl)?.CompositionTarget;
- if (src == null)
- return new Vector(1, 1);
- return new Vector(src.TransformToDevice.M11, src.TransformToDevice.M22);
- }
}
}