From f300a24402afc9f7f3c177e835a0cec10ce52e6c Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Mon, 29 May 2023 13:48:59 +0600 Subject: [PATCH 01/12] Media system refactoring - animation/layout/render cycle is now managed from a central location - animations are now throttled if animation/layout/render pass takes longer than a frame which previously caused a soft-freeze with input not being processed - the public API is trimmed to make sure that we can make other planned changes during the 11.x support cycle "Changelog": - IClock is hidden and is planned to be replaced later - Animator classes are hidden and are planned to be refactored later - IAnimation members are hidden, it's supposed to be a marker interface for Style.Animations collection now, to start animations manually use Animation.RunAsync - Sealed several classes in Avalonia.Animation namespace - Spring class is removed from the public API (it wasn't possible to use it directly in a meaningful way anyway) - Sealed brushes, transforms, effects and drawings - Removed separate dispatcher priorities for Layout and Composition, everything now happens from a central place with Render priority (same as WPF) - - some private "hook" priorities are added for now, those will be removed later - IRenderLoop is hidden and removed from locator - IRenderer is hidden (the plan is to remove that concept later) - - Renderer.Start/Stop exposed as StartRendering/StopRendering on the toplevel (will be on a CompositionTarget/PresentationSource-like type later) - - Renderer.Diagnistics exposed as RendererDiagnostics (same) - - Renderer is no longer created by the platform code and is created by TopLevel itself - - From the user-code hit-testing should be done by VisualExtensions.GetVisual(s)At, which has the same features - - For unit tests a separate IHitTester interface is added which can be changed for a particular toplevel - ILayoutManager is hidden - - LayoutManager.ExecuteLayoutPass() exposed as TopLevel.UpdateLayout() - Custom animators now have a separate base class that only deals with interpolation Minor improvements: - Compositor has a mode that doesn't use DispatcherTimers, useful for unit tests - Introduced ScopedTestBase that auto-resets the locator when test is finished --- nukebuild/RefAssemblyGenerator.cs | 38 +++- .../Pages/ItemsRepeaterPage.xaml.cs | 3 +- samples/GpuInterop/MainWindow.axaml.cs | 2 +- samples/RenderDemo/MainWindow.xaml.cs | 2 +- samples/RenderDemo/Pages/AnimationsPage.xaml | 4 - .../RenderDemo/Pages/AnimationsPage.xaml.cs | 15 -- .../RenderDemo/Pages/CustomAnimatorPage.xaml | 12 +- .../RenderDemo/Pages/CustomStringAnimator.cs | 5 +- .../RenderDemo/Pages/Transform3DPage.axaml | 3 - samples/RenderDemo/Pages/TransitionsPage.xaml | 4 - .../RenderDemo/Pages/TransitionsPage.xaml.cs | 15 -- .../Avalonia.Android/AndroidPlatform.cs | 1 - .../Platform/SkiaPlatform/TopLevelImpl.cs | 5 +- src/Avalonia.Base/Animation/Animatable.cs | 4 +- src/Avalonia.Base/Animation/Animation.cs | 26 ++- .../Animation/AnimatorDrivenTransition.cs | 9 +- .../Animation/AnimatorKeyFrame.cs | 2 +- .../Animation/AnimatorTransitionObservable.cs | 6 +- .../Animation/Animators/Animator`1.cs | 2 +- .../Animation/Animators/BaseBrushAnimator.cs | 2 +- .../Animation/Animators/BoolAnimator.cs | 2 +- .../Animation/Animators/BoxShadowAnimator.cs | 2 +- .../Animation/Animators/BoxShadowsAnimator.cs | 2 +- .../Animation/Animators/ByteAnimator.cs | 2 +- .../Animation/Animators/ColorAnimator.cs | 2 +- .../Animators/CornerRadiusAnimator.cs | 2 +- .../Animation/Animators/DecimalAnimator.cs | 2 +- .../Animation/Animators/DoubleAnimator.cs | 2 +- .../Animation/Animators/FloatAnimator.cs | 2 +- .../Animators/GradientBrushAnimator.cs | 2 +- .../Animation/Animators/Int16Animator.cs | 2 +- .../Animation/Animators/Int32Animator.cs | 2 +- .../Animation/Animators/Int64Animator.cs | 2 +- .../Animation/Animators/PointAnimator.cs | 2 +- .../Animation/Animators/RectAnimator.cs | 2 +- .../Animators/RelativePointAnimator.cs | 2 +- .../Animation/Animators/SizeAnimator.cs | 2 +- .../Animators/SolidColorBrushAnimator.cs | 2 +- .../Animation/Animators/ThicknessAnimator.cs | 2 +- .../Animation/Animators/TransformAnimator.cs | 2 +- .../Animators/TransformOperationsAnimator.cs | 2 +- .../Animation/Animators/UInt16Animator.cs | 2 +- .../Animation/Animators/UInt32Animator.cs | 2 +- .../Animation/Animators/UInt64Animator.cs | 2 +- .../Animation/Animators/VectorAnimator.cs | 2 +- src/Avalonia.Base/Animation/Clock.cs | 5 +- src/Avalonia.Base/Animation/ClockBase.cs | 2 +- .../Animation/Easings/SpringEasing.cs | 5 - src/Avalonia.Base/Animation/IAnimation.cs | 4 +- .../Animation/IAnimationSetter.cs | 2 +- src/Avalonia.Base/Animation/IAnimator.cs | 3 +- src/Avalonia.Base/Animation/IClock.cs | 3 +- .../Animation/ICustomAnimator.cs | 30 +++ src/Avalonia.Base/Animation/IGlobalClock.cs | 3 +- src/Avalonia.Base/Animation/ITransition.cs | 4 +- src/Avalonia.Base/Animation/KeyFrame.cs | 2 +- src/Avalonia.Base/Animation/KeyFrames.cs | 2 +- src/Avalonia.Base/Animation/KeySpline.cs | 2 +- .../Animation/RenderLoopClock.cs | 26 --- src/Avalonia.Base/Animation/Spring.cs | 2 +- .../Animation/SpringTypeConverter.cs | 2 +- src/Avalonia.Base/Animation/Transition.cs | 7 +- .../Animation/TransitionObservableBase.cs | 4 +- src/Avalonia.Base/Animation/Transitions.cs | 2 +- .../Transitions/BoxShadowsTransition.cs | 6 +- .../Animation/Transitions/BrushTransition.cs | 2 +- .../Animation/Transitions/ColorTransition.cs | 7 +- .../Transitions/CornerRadiusTransition.cs | 7 +- .../Animation/Transitions/DoubleTransition.cs | 5 +- .../Animation/Transitions/FloatTransition.cs | 5 +- .../Transitions/IntegerTransition.cs | 5 +- .../Animation/Transitions/PointTransition.cs | 5 +- .../Transitions/RelativePointTransition.cs | 5 +- .../Animation/Transitions/SizeTransition.cs | 5 +- .../Transitions/ThicknessTransition.cs | 5 +- .../TransformOperationsTransition.cs | 2 +- .../Animation/Transitions/VectorTransition.cs | 5 +- .../TextInput/TransformTrackingHelper.cs | 2 +- src/Avalonia.Base/Layout/ILayoutManager.cs | 2 +- src/Avalonia.Base/Layout/ILayoutRoot.cs | 2 +- src/Avalonia.Base/Layout/LayoutManager.cs | 9 +- src/Avalonia.Base/Media/DashStyle.cs | 2 +- src/Avalonia.Base/Media/Drawing.cs | 5 + src/Avalonia.Base/Media/DrawingBrush.cs | 2 +- src/Avalonia.Base/Media/DrawingGroup.cs | 2 +- src/Avalonia.Base/Media/Effects/BlurEffect.cs | 2 +- .../Media/Effects/DropShadowEffect.cs | 4 +- src/Avalonia.Base/Media/Effects/Effect.cs | 5 + .../Media/Effects/EffectAnimator.cs | 8 +- .../Media/Effects/EffectTransition.cs | 2 +- src/Avalonia.Base/Media/GeometryDrawing.cs | 2 +- src/Avalonia.Base/Media/GlyphRunDrawing.cs | 2 +- src/Avalonia.Base/Media/GradientBrush.cs | 2 +- src/Avalonia.Base/Media/ImageBrush.cs | 2 +- src/Avalonia.Base/Media/ImageDrawing.cs | 2 +- src/Avalonia.Base/Media/MatrixTransform.cs | 2 +- src/Avalonia.Base/Media/MediaContext.Clock.cs | 53 ++++++ .../Media/MediaContext.Compositor.cs | 135 ++++++++++++++ src/Avalonia.Base/Media/MediaContext.cs | 171 ++++++++++++++++++ src/Avalonia.Base/Media/RotateTransform.cs | 2 +- src/Avalonia.Base/Media/ScaleTransform.cs | 2 +- src/Avalonia.Base/Media/SkewTransform.cs | 2 +- src/Avalonia.Base/Media/SolidColorBrush.cs | 2 +- src/Avalonia.Base/Media/TileBrush.cs | 5 + src/Avalonia.Base/Media/Transform.cs | 5 + src/Avalonia.Base/Media/TransformGroup.cs | 2 +- src/Avalonia.Base/Media/TranslateTransform.cs | 2 +- src/Avalonia.Base/Media/VisualBrush.cs | 2 +- .../Metadata/PrivateApiAttribute.cs | 3 +- .../Composition/CompositingRenderer.cs | 25 +-- .../Composition/CompositionTarget.cs | 9 - .../Rendering/Composition/Compositor.cs | 90 +++++---- .../Server/ServerCompositionTarget.cs | 30 +-- .../Composition/Server/ServerCompositor.cs | 29 ++- .../Rendering/Composition/Transport/Batch.cs | 16 +- .../Transport/BatchStreamArrayPool.cs | 15 +- src/Avalonia.Base/Rendering/IRenderLoop.cs | 2 +- .../Rendering/IRenderLoopTask.cs | 4 +- src/Avalonia.Base/Rendering/IRenderRoot.cs | 4 +- src/Avalonia.Base/Rendering/IRenderer.cs | 58 +++--- src/Avalonia.Base/Rendering/RenderLoop.cs | 71 ++------ .../Rendering/UiThreadRenderTimer.cs | 2 +- src/Avalonia.Base/Rotate3DTransform.cs | 2 +- .../Threading/DispatcherPriority.cs | 47 +++-- .../VisualTree/VisualExtensions.cs | 4 +- src/Avalonia.Controls/Application.cs | 7 +- .../Avalonia.Controls.csproj | 2 + .../Embedding/EmbeddableControlRoot.cs | 4 + .../Offscreen/OffscreenTopLevelImpl.cs | 10 +- src/Avalonia.Controls/NativeControlHost.cs | 2 +- .../Platform/ITopLevelImpl.cs | 6 +- .../Presenters/TextPresenter.cs | 2 +- .../Primitives/OverlayPopupHost.cs | 2 +- .../Remote/Server/RemoteServerTopLevelImpl.cs | 8 +- src/Avalonia.Controls/TopLevel.cs | 37 +++- src/Avalonia.Controls/Window.cs | 10 +- src/Avalonia.Controls/WindowBase.cs | 4 +- .../Remote/PreviewerWindowingPlatform.cs | 1 - src/Avalonia.DesignerSupport/Remote/Stubs.cs | 6 +- src/Avalonia.Native/AvaloniaNativePlatform.cs | 7 +- src/Avalonia.Native/WindowImplBase.cs | 12 +- src/Avalonia.X11/X11Platform.cs | 3 +- src/Avalonia.X11/X11Window.cs | 9 +- .../Avalonia.Browser/BrowserTopLevelImpl.cs | 9 +- .../Avalonia.Browser/WindowingPlatform.cs | 1 - .../AvaloniaHeadlessPlatform.cs | 5 +- .../Avalonia.Headless/HeadlessWindowImpl.cs | 3 +- .../FramebufferToplevelImpl.cs | 5 +- .../LinuxFramebufferPlatform.cs | 10 +- src/Windows/Avalonia.Win32/Win32Platform.cs | 3 +- .../WindowImpl.CustomCaptionProc.cs | 3 +- src/Windows/Avalonia.Win32/WindowImpl.cs | 3 +- src/iOS/Avalonia.iOS/AvaloniaView.cs | 4 +- src/iOS/Avalonia.iOS/Platform.cs | 1 - .../Composition/BatchStreamTests.cs | 4 +- .../Composition/CompositionAnimationTests.cs | 3 +- .../Input/MouseDeviceTests.cs | 19 +- .../Input/PointerOverTests.cs | 75 ++++---- .../Input/PointerTestsBase.cs | 13 +- .../Layout/LayoutManagerTests.cs | 5 +- ...ayoutableTests_EffectiveViewportChanged.cs | 5 + .../Rendering/RenderLoopTests.cs | 113 ------------ .../SceneGraph/DrawOperationTests.cs | 4 +- .../Styling/StyleTests.cs | 2 +- .../Styling/StyledElementTests.cs | 4 +- .../Styling/StyledElementTests_Theming.cs | 8 +- tests/Avalonia.Base.UnitTests/VisualTests.cs | 2 +- .../ButtonTests.cs | 12 +- .../ContextMenuTests.cs | 5 +- .../DesktopStyleApplicationLifetimeTests.cs | 4 +- .../FlyoutTests.cs | 4 +- .../GridSplitterTests.cs | 2 +- .../Avalonia.Controls.UnitTests/GridTests.cs | 2 +- .../ListBoxTests.cs | 2 +- .../MaskedTextBoxTests.cs | 4 +- .../Primitives/PopupTests.cs | 32 ++-- .../Primitives/SelectingItemsControlTests.cs | 2 +- .../ScrollViewerTests.cs | 2 +- .../TextBoxTests.cs | 4 +- .../TopLevelTests.cs | 34 ++-- .../TreeViewTests.cs | 2 +- .../VirtualizingStackPanelTests.cs | 2 +- .../WindowBaseTests.cs | 53 +++--- .../WindowTests.cs | 39 ++-- tests/Avalonia.LeakTests/ControlTests.cs | 7 +- .../AvaloniaPropertyConverterTest.cs | 2 +- .../PointsListTypeConverterTests.cs | 2 +- .../Xaml/ControlThemeTests.cs | 2 - .../Xaml/StyleTests.cs | 4 +- .../XamlTestBase.cs | 17 +- tests/Avalonia.RenderTests/TestBase.cs | 4 +- tests/Avalonia.RenderTests/TestRenderRoot.cs | 14 +- .../Avalonia.UnitTests.csproj | 1 + .../CompositorTestServices.cs | 26 +-- .../Avalonia.UnitTests/InternalsVisibleTo.cs | 11 ++ tests/Avalonia.UnitTests/MockGlobalClock.cs | 2 +- .../MockWindowingPlatform.cs | 9 +- tests/Avalonia.UnitTests/RendererMocks.cs | 23 ++- tests/Avalonia.UnitTests/ScopedTestBase.cs | 18 ++ tests/Avalonia.UnitTests/TestRoot.cs | 18 +- tests/Avalonia.UnitTests/TestServices.cs | 37 +++- 201 files changed, 1254 insertions(+), 821 deletions(-) create mode 100644 src/Avalonia.Base/Animation/ICustomAnimator.cs delete mode 100644 src/Avalonia.Base/Animation/RenderLoopClock.cs create mode 100644 src/Avalonia.Base/Media/MediaContext.Clock.cs create mode 100644 src/Avalonia.Base/Media/MediaContext.Compositor.cs create mode 100644 src/Avalonia.Base/Media/MediaContext.cs delete mode 100644 tests/Avalonia.Base.UnitTests/Rendering/RenderLoopTests.cs create mode 100644 tests/Avalonia.UnitTests/InternalsVisibleTo.cs create mode 100644 tests/Avalonia.UnitTests/ScopedTestBase.cs diff --git a/nukebuild/RefAssemblyGenerator.cs b/nukebuild/RefAssemblyGenerator.cs index e1c19c69a3..dc96849fe7 100644 --- a/nukebuild/RefAssemblyGenerator.cs +++ b/nukebuild/RefAssemblyGenerator.cs @@ -71,10 +71,10 @@ public class RefAssemblyGenerator foreach (var nested in type.NestedTypes) ProcessType(nested, obsoleteCtor); - var hideMethods = (type.IsInterface && type.Name.EndsWith("Impl")) + var hideMembers = (type.IsInterface && type.Name.EndsWith("Impl")) || HasPrivateApi(type.CustomAttributes); - var injectMethod = hideMethods + var injectMethod = hideMembers || type.CustomAttributes.Any(a => a.AttributeType.FullName == "Avalonia.Metadata.NotClientImplementableAttribute"); @@ -95,21 +95,47 @@ public class RefAssemblyGenerator foreach (var m in type.Methods) { - if (hideMethods || HasPrivateApi(m.CustomAttributes)) + if (hideMembers || HasPrivateApi(m.CustomAttributes)) { - var dflags = MethodAttributes.Public | MethodAttributes.Family | MethodAttributes.FamORAssem | - MethodAttributes.FamANDAssem | MethodAttributes.Assembly; - m.Attributes = ((m.Attributes | dflags) ^ dflags) | MethodAttributes.Assembly; + HideMethod(m); } MarkAsUnstable(m, obsoleteCtor, forceUnstable); } + foreach (var p in type.Properties) + { + if (HasPrivateApi(p.CustomAttributes)) + { + if (p.SetMethod != null) + HideMethod(p.SetMethod); + if (p.GetMethod != null) + HideMethod(p.GetMethod); + } + } + + foreach (var f in type.Fields) + { + if (hideMembers || HasPrivateApi(f.CustomAttributes)) + { + var dflags = FieldAttributes.Public | FieldAttributes.Family | FieldAttributes.FamORAssem | + FieldAttributes.FamANDAssem | FieldAttributes.Assembly; + f.Attributes = ((f.Attributes | dflags) ^ dflags) | FieldAttributes.Assembly; + } + } + foreach (var m in type.Properties) MarkAsUnstable(m, obsoleteCtor, forceUnstable); foreach (var m in type.Events) MarkAsUnstable(m, obsoleteCtor, forceUnstable); } + static void HideMethod(MethodDefinition m) + { + var dflags = MethodAttributes.Public | MethodAttributes.Family | MethodAttributes.FamORAssem | + MethodAttributes.FamANDAssem | MethodAttributes.Assembly; + m.Attributes = ((m.Attributes | dflags) ^ dflags) | MethodAttributes.Assembly; + } + static void MarkAsUnstable(IMemberDefinition def, MethodReference obsoleteCtor, ICustomAttribute unstableAttribute) { if (def.CustomAttributes.Any(a => a.AttributeType.FullName == "System.ObsoleteAttribute")) diff --git a/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs b/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs index 70ce6107ad..2219966daa 100644 --- a/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs +++ b/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs @@ -117,9 +117,8 @@ namespace ControlCatalog.Pages private void ScrollTo(int index) { System.Diagnostics.Debug.WriteLine("Scroll to " + index); - var layoutManager = ((TopLevel)VisualRoot!).LayoutManager; var element = _repeater.GetOrCreateElement(index); - layoutManager.ExecuteLayoutPass(); + ((TopLevel)VisualRoot!).UpdateLayout(); element.BringIntoView(); } diff --git a/samples/GpuInterop/MainWindow.axaml.cs b/samples/GpuInterop/MainWindow.axaml.cs index 7cf0bc00e2..8d359fe7ef 100644 --- a/samples/GpuInterop/MainWindow.axaml.cs +++ b/samples/GpuInterop/MainWindow.axaml.cs @@ -11,7 +11,7 @@ namespace GpuInterop { InitializeComponent(); this.AttachDevTools(); - Renderer.Diagnostics.DebugOverlays = RendererDebugOverlays.Fps; + RendererDiagnostics.DebugOverlays = RendererDebugOverlays.Fps; } private void InitializeComponent() diff --git a/samples/RenderDemo/MainWindow.xaml.cs b/samples/RenderDemo/MainWindow.xaml.cs index d85f3b6051..be47ffd6e9 100644 --- a/samples/RenderDemo/MainWindow.xaml.cs +++ b/samples/RenderDemo/MainWindow.xaml.cs @@ -21,7 +21,7 @@ namespace RenderDemo void BindOverlay(Expression> expr, RendererDebugOverlays overlay) => vm.WhenAnyValue(expr).Subscribe(x => { - var diagnostics = Renderer.Diagnostics; + var diagnostics = RendererDiagnostics; diagnostics.DebugOverlays = x ? diagnostics.DebugOverlays | overlay : diagnostics.DebugOverlays & ~overlay; diff --git a/samples/RenderDemo/Pages/AnimationsPage.xaml b/samples/RenderDemo/Pages/AnimationsPage.xaml index d764af8978..f80389c832 100644 --- a/samples/RenderDemo/Pages/AnimationsPage.xaml +++ b/samples/RenderDemo/Pages/AnimationsPage.xaml @@ -347,12 +347,8 @@ - - - Hover to activate Keyframe Animations. -