diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositedWindow.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositedWindow.cs index da56c98d56..e9b002a208 100644 --- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositedWindow.cs +++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositedWindow.cs @@ -1,5 +1,7 @@ using System; using System.Numerics; +using System.Reactive.Disposables; +using System.Threading; using Avalonia.MicroCom; using Avalonia.OpenGL; using Avalonia.OpenGL.Egl; @@ -10,6 +12,7 @@ namespace Avalonia.Win32.WinRT.Composition public class WinUICompositedWindow : IDisposable { private EglContext _syncContext; + private readonly object _pumpLock; private readonly IVisual _blurVisual; private ICompositionTarget _compositionTarget; private IVisual _contentVisual; @@ -17,14 +20,19 @@ namespace Avalonia.Win32.WinRT.Composition private PixelSize _size; private static Guid IID_ID3D11Texture2D = Guid.Parse("6f15aaf2-d208-4e89-9ab4-489535d34f9c"); - + private ICompositor _compositor; + internal WinUICompositedWindow(EglContext syncContext, + ICompositor compositor, + object pumpLock, ICompositionTarget compositionTarget, ICompositionDrawingSurfaceInterop surfaceInterop, IVisual contentVisual, IVisual blurVisual) { + _compositor = compositor.CloneReference(); _syncContext = syncContext; + _pumpLock = pumpLock; _blurVisual = blurVisual.CloneReference(); _compositionTarget = compositionTarget.CloneReference(); _contentVisual = contentVisual.CloneReference(); @@ -36,7 +44,7 @@ namespace Avalonia.Win32.WinRT.Composition { using (_syncContext.EnsureLocked()) { - if (_size != size) + //if (_size != size) { _surfaceInterop.Resize(new UnmanagedMethods.POINT { X = size.Width, Y = size.Height }); _contentVisual.SetSize(new Vector2(size.Width, size.Height)); @@ -70,10 +78,26 @@ namespace Avalonia.Win32.WinRT.Composition _blurVisual.SetIsVisible(enable ? 1 : 0); } + public IDisposable BeginTransaction() + { + Monitor.Enter(_pumpLock); + //var batch = _compositor.CreateScopedBatch(CompositionBatchTypes.Effect); + + return Disposable.Create(() => + { + Monitor.Exit(_pumpLock); + /* + batch?.End(); + batch?.Dispose(); + batch = null;*/ + }); + } + public void Dispose() { if (_syncContext == null) { + _compositor.Dispose(); _blurVisual.Dispose(); _contentVisual.Dispose(); _surfaceInterop.Dispose(); diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositorConnection.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositorConnection.cs index 8be68bbfe2..393019b547 100644 --- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositorConnection.cs +++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositorConnection.cs @@ -25,10 +25,12 @@ namespace Avalonia.Win32.WinRT.Composition private EglPlatformOpenGlInterface _gl; private ICompositorDesktopInterop _compositorDesktopInterop; private ICompositionBrush _blurBrush; + private object _pumpLock = new object(); - public WinUICompositorConnection(EglPlatformOpenGlInterface gl) + public WinUICompositorConnection(EglPlatformOpenGlInterface gl, object pumpLock) { _gl = gl; + _pumpLock = pumpLock; _syncContext = _gl.PrimaryEglContext; _angle = (AngleWin32EglDisplay)_gl.Display; _compositor = NativeWinRTMethods.CreateInstance("Windows.UI.Composition.Compositor"); @@ -46,6 +48,7 @@ namespace Avalonia.Win32.WinRT.Composition static WinUICompositorConnection TryCreateCore(EglPlatformOpenGlInterface angle) { var tcs = new TaskCompletionSource(); + var pumpLock = new object(); var th = new Thread(() => { try @@ -56,11 +59,16 @@ namespace Avalonia.Win32.WinRT.Composition dwSize = Marshal.SizeOf(), threadType = NativeWinRTMethods.DISPATCHERQUEUE_THREAD_TYPE.DQTYPE_THREAD_CURRENT }); - tcs.SetResult(new WinUICompositorConnection(angle)); + tcs.SetResult(new WinUICompositorConnection(angle, pumpLock)); while (true) { - while (UnmanagedMethods.GetMessage(out var msg, IntPtr.Zero, 0, 0) != 0) - UnmanagedMethods.DispatchMessage(ref msg); + while (true) + { + if (UnmanagedMethods.GetMessage(out var msg, IntPtr.Zero, 0, 0) == 0) + return; + lock (pumpLock) + UnmanagedMethods.DispatchMessage(ref msg); + } } } catch (Exception e) @@ -141,7 +149,7 @@ namespace Avalonia.Win32.WinRT.Composition containerChildren.InsertAtTop(blur); containerChildren.InsertAtTop(visual); - return new WinUICompositedWindow(_syncContext, target, surfaceInterop, visual, blur); + return new WinUICompositedWindow(_syncContext, _compositor, _pumpLock, target, surfaceInterop, visual, blur); } diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs index cc9952c226..f59d50860a 100644 --- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs +++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs @@ -60,6 +60,7 @@ namespace Avalonia.Win32.WinRT.Composition var contextLock = _egl.PrimaryEglContext.EnsureCurrent(); IUnknown texture = null; EglSurface surface = null; + IDisposable transaction = null; var success = false; try { @@ -67,6 +68,7 @@ namespace Avalonia.Win32.WinRT.Composition throw new ObjectDisposedException(GetType().FullName); var size = _info.Size; + transaction = _window.Item.BeginTransaction(); _window.Item.ResizeIfNeeded(size); texture = _window.Item.BeginDrawToTexture(out var offset); @@ -79,6 +81,7 @@ namespace Avalonia.Win32.WinRT.Composition surface?.Dispose(); texture?.Dispose(); _window.Item.EndDraw(); + transaction?.Dispose(); contextLock?.Dispose(); }, true); success = true; @@ -90,6 +93,7 @@ namespace Avalonia.Win32.WinRT.Composition { surface?.Dispose(); texture?.Dispose(); + transaction?.Dispose(); contextLock.Dispose(); } } diff --git a/src/Windows/Avalonia.Win32/WinRT/winrt.idl b/src/Windows/Avalonia.Win32/WinRT/winrt.idl index 9107eecd42..bdc757138c 100644 --- a/src/Windows/Avalonia.Win32/WinRT/winrt.idl +++ b/src/Windows/Avalonia.Win32/WinRT/winrt.idl @@ -328,7 +328,7 @@ interface ICompositor : IInspectable HRESULT CreatePropertySet([out] [retval] void** result); HRESULT CreateQuaternionKeyFrameAnimation([out] [retval] void** result); HRESULT CreateScalarKeyFrameAnimation([out] [retval] void** result); - HRESULT CreateScopedBatch([in] CompositionBatchTypes batchType, [out] [retval] void** result); + HRESULT CreateScopedBatch([in] CompositionBatchTypes batchType, [out] [retval] ICompositionScopedBatch** result); HRESULT CreateSpriteVisual([out] [retval] ISpriteVisual** result); HRESULT CreateSurfaceBrush([out] [retval] ICompositionSurfaceBrush** result); HRESULT CreateSurfaceBrushWithSurface([in] ICompositionSurface* surface, @@ -456,11 +456,41 @@ interface ICompositionDrawingSurface : IInspectable [propget] HRESULT GetSize([out] [retval] POINT* value); } +enum CompositionBitmapInterpolationMode +{ + NearestNeighbor, + Linear, + MagLinearMinLinearMipLinear, + MagLinearMinLinearMipNearest, + MagLinearMinNearestMipLinear, + MagLinearMinNearestMipNearest, + MagNearestMinLinearMipLinear, + MagNearestMinLinearMipNearest, + MagNearestMinNearestMipLinear, + MagNearestMinNearestMipNearest, +} + +enum CompositionStretch +{ + None, + Fill, + Uniform, + UniformToFill, +} [uuid(AD016D79-1E4C-4C0D-9C29-83338C87C162)] interface ICompositionSurfaceBrush : IInspectable { - //TODO + [propget] HRESULT BitmapInterpolationMode([out] [retval] CompositionBitmapInterpolationMode* value); + [propput] HRESULT BitmapInterpolationMode([in] CompositionBitmapInterpolationMode value); + [propget] HRESULT HorizontalAlignmentRatio([out] [retval] FLOAT* value); + [propput] HRESULT HorizontalAlignmentRatio([in] FLOAT value); + [propget] HRESULT Stretch([out] [retval] CompositionStretch* value); + [propput] HRESULT Stretch([in] CompositionStretch value); + [propget] HRESULT Surface([out] [retval] ICompositionSurface** value); + [propput] HRESULT Surface([in] ICompositionSurface* value); + [propget] HRESULT VerticalAlignmentRatio([out] [retval] FLOAT* value); + [propput] HRESULT VerticalAlignmentRatio([in] FLOAT value); } [uuid(AB0D7608-30C0-40E9-B568-B60A6BD1FB46)] @@ -649,3 +679,15 @@ interface ICompositionColorBrush : IInspectable [propget] HRESULT Color([out] [retval] Color* value); [propput] HRESULT Color([in] Color value); } + +[uuid(0D00DAD0-FB07-46FD-8C72-6280D1A3D1DD)] +interface ICompositionScopedBatch : IInspectable +{ + [propget] HRESULT IsActive([out] [retval] boolean* value); + [propget] HRESULT IsEnded([out] [retval] boolean* value); + HRESULT End(); + HRESULT Resume(); + HRESULT Suspend(); + [eventadd] HRESULT AddCompleted([in] void* handler, [out] [retval] int* token); + [eventremove] HRESULT RemoveCompleted([in] int token); +} diff --git a/src/tools/MicroComGenerator/CSharpGen.cs b/src/tools/MicroComGenerator/CSharpGen.cs index c74e7af12e..ff4c351fd9 100644 --- a/src/tools/MicroComGenerator/CSharpGen.cs +++ b/src/tools/MicroComGenerator/CSharpGen.cs @@ -121,7 +121,8 @@ namespace MicroComGenerator NamespaceDeclarationSyntax GenerateEnums(NamespaceDeclarationSyntax ns) { return ns.AddMembers(_idl.Enums.Select(e => - EnumDeclaration(e.Name) + { + var dec = EnumDeclaration(e.Name) .WithModifiers(TokenList(Token(_visibility))) .WithMembers(SeparatedList(e.Select(m => { @@ -129,8 +130,11 @@ namespace MicroComGenerator if (m.Value != null) return member.WithEqualsValue(EqualsValueClause(ParseExpression(m.Value))); return member; - }))) - ).ToArray()); + }))); + if (e.HasAttribute("flags")) + dec = dec.AddAttribute("System.Flags"); + return dec; + }).ToArray()); } NamespaceDeclarationSyntax GenerateStructs(NamespaceDeclarationSyntax ns)