| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- using System;
- using System.Runtime.InteropServices;
- using System.Windows;
- using System.Windows.Interop;
- using Avalonia.Direct2D1;
- 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 Query = SharpDX.Direct3D11.Query;
- using QueryType = SharpDX.Direct3D11.QueryType;
- using RenderTarget = SharpDX.Direct2D1.RenderTarget;
- using Surface = SharpDX.DXGI.Surface;
- using Usage = SharpDX.Direct3D9.Usage;
- namespace Avalonia.Win32.Interop.Wpf
- {
- class Direct2DImageSurface : IExternalDirect2DRenderTargetSurface, IDisposable
- {
- class SwapBuffer: IDisposable
- {
- private readonly Query _event;
- private readonly SharpDX.Direct3D11.Resource _resource;
- private readonly SharpDX.Direct3D11.Resource _sharedResource;
- public SharpDX.Direct3D9.Surface Texture { get; }
- public RenderTarget Target { get;}
- public IntSize Size { get; }
- public SwapBuffer(IntSize size, Vector dpi)
- {
- int width = (int) size.Width;
- int height = (int) size.Height;
- _event = new Query(s_dxDevice, new QueryDescription {Type = QueryType.Event});
- 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(2, 0),
- BindFlags = BindFlags.RenderTarget,
- }))
- using (var surface = texture.QueryInterface<Surface>())
-
- {
- _resource = texture.QueryInterface<SharpDX.Direct3D11.Resource>();
-
- Target = new RenderTarget(Direct2D1Platform.Direct2D1Factory, 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 = 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 resource = texture.QueryInterface<SharpDX.DXGI.Resource>())
- {
- _sharedResource = texture.QueryInterface<SharpDX.Direct3D11.Resource>();
- 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);
- }
- Size = size;
- }
- public void Dispose()
- {
- Texture?.Dispose();
- Target?.Dispose();
- _resource?.Dispose();
- _sharedResource?.Dispose();
- _event?.Dispose();
- }
- public void Flush()
- {
- s_dxDevice.ImmediateContext.ResolveSubresource(_resource, 0, _sharedResource, 0, Format.B8G8R8A8_UNorm);
- s_dxDevice.ImmediateContext.Flush();
- s_dxDevice.ImmediateContext.End(_event);
- s_dxDevice.ImmediateContext.GetData(_event).Dispose();
- }
- }
- private D3DImage _image;
- private SwapBuffer _backBuffer;
- private readonly WpfTopLevelImpl _impl;
- private static Device s_dxDevice;
- private static Direct3DEx s_d3DContext;
- private static DeviceEx s_d3DDevice;
- private Vector _oldDpi;
- [DllImport("user32.dll", SetLastError = false)]
- private static extern IntPtr GetDesktopWindow();
- static 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<SharpDX.DXGI.Device>()
- .QueryInterface<SharpDX.Direct3D11.Device>();
- 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 IntSize(_impl.ActualWidth * scale.X, _impl.ActualHeight * scale.Y);
- var dpi = scale * 96;
- if (_backBuffer!=null && _backBuffer.Size == size)
- return _backBuffer.Target;
- if (_image == null || _oldDpi.X != dpi.X || _oldDpi.Y != dpi.Y)
- {
- _image = new D3DImage(dpi.X, dpi.Y);
- _oldDpi = dpi;
- }
- _impl.ImageSource = _image;
- RemoveAndDispose(ref _backBuffer);
- if (size == default(IntSize))
- {
- _image.Lock();
- _image.SetBackBuffer(D3DResourceType.IDirect3DSurface9, IntPtr.Zero);
- _image.Unlock();
- return null;
- }
- _backBuffer = new SwapBuffer(size, dpi);
- return _backBuffer.Target;
- }
- static void RemoveAndDispose<T>(ref T d) where T : IDisposable
- {
- d?.Dispose();
- d = default(T);
- }
- void Swap()
- {
- _backBuffer.Flush();
- _image.Lock();
- _image.SetBackBuffer(D3DResourceType.IDirect3DSurface9, _backBuffer?.Texture?.NativePointer ?? IntPtr.Zero, true);
- _image.AddDirtyRect(new Int32Rect(0, 0, _image.PixelWidth, _image.PixelHeight));
- _image.Unlock();
- }
- public void DestroyRenderTarget()
- {
- RemoveAndDispose(ref _backBuffer);
- }
- public void BeforeDrawing()
- {
-
- }
- public void AfterDrawing() => Swap();
- public void Dispose()
- {
- RemoveAndDispose(ref _backBuffer);
- }
- }
- }
|