Skip to content

Commit

Permalink
Merge pull request unoplatform#16403 from ramezgerges/composition_thr…
Browse files Browse the repository at this point in the history
…ead_architecture

Skia Composition refactoring
  • Loading branch information
ramezgerges authored May 9, 2024
2 parents 4bf72fb + 284ea63 commit ef7b6a1
Show file tree
Hide file tree
Showing 29 changed files with 432 additions and 539 deletions.
1 change: 1 addition & 0 deletions src/SamplesApp/UITests.Shared/UITests.Shared.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -8104,6 +8104,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Media\BrushesTests\Brushes_ImplicitConvert.xaml.cs">
<DependentUpon>Brushes_ImplicitConvert.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Media\BrushesTests\CompositionNineGridBrush_Source_Changes.xaml.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Media\BrushesTests\ColorPresenter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Media\BrushesTests\DynamicBrushes_On_Shapes.xaml.cs">
<DependentUpon>DynamicBrushes_On_Shapes.xaml</DependentUpon>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
using System;
using Microsoft.UI.Composition;
using Uno.UI.Samples.Controls;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Hosting;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Media.Imaging;

namespace UITests.Windows_UI_Xaml_Media.BrushesTests
{
[Sample("Brushes")]
public sealed partial class CompositionNineGridBrush_Source_Changes : Page
{
public CompositionNineGridBrush_Source_Changes()
{
var compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;

var onlineSource = new Image
{
Width = 100,
Height = 100,
Stretch = Stretch.UniformToFill,
Source = new BitmapImage(new Uri("ms-appx:///Assets/test_image_100_100.png"))
};

var online = new Border
{
Width = 200,
Height = 200
};

var offline = new Grid
{
Width = 200,
Height = 200
};

var visualSurface = compositor.CreateVisualSurface();
visualSurface.SourceVisual = ElementCompositionPreview.GetElementVisual(onlineSource);
visualSurface.SourceSize = new(200, 200);

var onlineBrush = compositor.CreateSurfaceBrush(visualSurface);
var onlineNineGridBrush = compositor.CreateNineGridBrush();
onlineNineGridBrush.Source = onlineBrush;
onlineNineGridBrush.SetInsets(35);

online.Background = new TestBrush(onlineNineGridBrush);

var surface = Microsoft.UI.Xaml.Media.LoadedImageSurface.StartLoadFromUri(new Uri("ms-appx:///Assets/test_image_100_100.png"));

surface.LoadCompleted += new Windows.Foundation.TypedEventHandler<Microsoft.UI.Xaml.Media.LoadedImageSurface, LoadedImageSourceLoadCompletedEventArgs>((s, o) =>
{
if (o.Status == Microsoft.UI.Xaml.Media.LoadedImageSourceLoadStatus.Success)
{
var offlineBrush = compositor.CreateSurfaceBrush(surface);

var offlineNineGridBrush = compositor.CreateNineGridBrush();
offlineNineGridBrush.Source = offlineBrush;
offlineNineGridBrush.SetInsets(35);

offline.Background = new TestBrush(offlineNineGridBrush);

this.Content = new StackPanel
{
Children =
{
onlineSource,
// we need to put the children in borders to work around our limited implementation of RenderTargetBitmap
// not taking the offsets of the Visuals into account. This way, the Child will not have any offset
// relative to its parent (the border)
new Border
{
Child = online
},
new Border
{
Child = offline
}
}
};
}
});
}

private class TestBrush : Microsoft.UI.Xaml.Media.XamlCompositionBrushBase
{
private CompositionBrush Brush;

public TestBrush(CompositionBrush brush) => Brush = brush;

protected override void OnConnected() => CompositionBrush = Brush;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ internal override void UpdatePaint(SKPaint paint, SKRect bounds)
paint.Shader = SKShader.CreateCompose(_sourcePaint.Shader, _maskPaint.Shader, SKBlendMode.DstIn);
}

void IOnlineBrush.Draw(in DrawingSession session, SKRect bounds)
void IOnlineBrush.Paint(in Visual.PaintingSession session, SKRect bounds)
{
_resultPaint ??= new SKPaint() { IsAntialias = true };

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ internal override void UpdatePaint(SKPaint paint, SKRect bounds)
}
}

void IOnlineBrush.Draw(in DrawingSession session, SKRect bounds)
void IOnlineBrush.Paint(in Visual.PaintingSession session, SKRect bounds)
{
SKRect sourceBounds;
if (Source is ISizedBrush sizedBrush && sizedBrush.IsSized && sizedBrush.Size is Vector2 sourceSize)
Expand Down
148 changes: 70 additions & 78 deletions src/Uno.UI.Composition/Composition/CompositionObject.Context.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,118 +7,110 @@ namespace Microsoft.UI.Composition
{
public partial class CompositionObject
{
private class ContextStore
{
private readonly object _lock = new object();
private List<ContextEntry>? _contextEntries;
private readonly object _contextEntriesLock = new object();
private List<ContextEntry>? _contextEntries;

public ContextStore()
public void AddContext(CompositionObject context, string? propertyName)
{
lock (_contextEntriesLock)
{

AddContextImpl(context, propertyName);
}
}

public void AddContext(CompositionObject context, string? propertyName)
public void RemoveContext(CompositionObject context, string? propertyName)
{
lock (_contextEntriesLock)
{
lock (_lock)
{
AddContextImpl(context, propertyName);
}
RemoveContextImpl(context, propertyName);
}
}

public void RemoveContext(CompositionObject context, string? propertyName)
public void PropagateChanged()
{
lock (_contextEntriesLock)
{
lock (_lock)
{
RemoveContextImpl(context, propertyName);
}
PropagateChangedImpl();
}
}

public void RaiseChanged()
private void AddContextImpl(CompositionObject newContext, string? propertyName)
{
var contextEntries = _contextEntries;
if (contextEntries == null)
{
lock (_lock)
{
RaiseChangedImpl();
}
contextEntries = new List<ContextEntry>();
_contextEntries = contextEntries;
}

private void AddContextImpl(CompositionObject newContext, string? propertyName)
{
var contextEntries = _contextEntries;
if (contextEntries == null)
{
contextEntries = new List<ContextEntry>();
_contextEntries = contextEntries;
}
contextEntries.Add(new ContextEntry(newContext, propertyName));
}

contextEntries.Add(new ContextEntry(newContext, propertyName));
private void RemoveContextImpl(CompositionObject oldContext, string? propertyName)
{
var contextEntries = _contextEntries;
if (contextEntries == null)
{
return;
}

private void RemoveContextImpl(CompositionObject oldContext, string? propertyName)
for (int i = contextEntries.Count - 1; i >= 0; i--)
{
var contextEntries = _contextEntries;
if (contextEntries == null)
{
return;
}
var contextEntry = contextEntries[i];

for (int i = contextEntries.Count - 1; i >= 0; i--)
if (!contextEntry.Context.TryGetTarget(out CompositionObject? context))
{
var contextEntry = contextEntries[i];

if (!contextEntry.Context.TryGetTarget(out CompositionObject? context))
{
// Clean up dead references.
contextEntries.RemoveAt(i);
continue;
}

if (context == oldContext && contextEntry.PropertyName == propertyName)
{
contextEntries.RemoveAt(i);
break;
}
// Clean up dead references.
contextEntries.RemoveAt(i);
continue;
}

if (contextEntries.Count == 0)
if (context == oldContext && contextEntry.PropertyName == propertyName)
{
_contextEntries = null;
contextEntries.RemoveAt(i);
break;
}
}

private void RaiseChangedImpl()
if (contextEntries.Count == 0)
{
var contextEntries = _contextEntries;
if (contextEntries == null)
{
return;
}

for (int i = contextEntries.Count - 1; i >= 0; i--)
{
var contextEntry = contextEntries[i];

if (!contextEntry.Context.TryGetTarget(out CompositionObject? context))
{
// Clean up dead references.
contextEntries.RemoveAt(i);
continue;
}
_contextEntries = null;
}
}

context!.OnPropertyChanged(contextEntry.PropertyName, true);
}
private void PropagateChangedImpl()
{
var contextEntries = _contextEntries;
if (contextEntries == null)
{
return;
}

private class ContextEntry
for (int i = contextEntries.Count - 1; i >= 0; i--)
{
public ContextEntry(CompositionObject context, string? propertyName)
var contextEntry = contextEntries[i];

if (!contextEntry.Context.TryGetTarget(out var context))
{
Context = new WeakReference<CompositionObject>(context);
PropertyName = propertyName;
// Clean up dead references.
contextEntries.RemoveAt(i);
continue;
}

public WeakReference<CompositionObject> Context { get; }
public string? PropertyName { get; }
context.OnPropertyChanged(contextEntry.PropertyName, true);
}
}

private class ContextEntry
{
public ContextEntry(CompositionObject context, string? propertyName)
{
Context = new WeakReference<CompositionObject>(context);
PropertyName = propertyName;
}

public WeakReference<CompositionObject> Context { get; }
public string? PropertyName { get; }
}
}
}
13 changes: 1 addition & 12 deletions src/Uno.UI.Composition/Composition/CompositionObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ namespace Microsoft.UI.Composition
{
public partial class CompositionObject : IDisposable
{
private readonly ContextStore _contextStore = new ContextStore();
private CompositionPropertySet? _properties;
private Dictionary<string, CompositionAnimation>? _animations;

Expand Down Expand Up @@ -157,16 +156,6 @@ internal virtual bool StartAnimationCore(string propertyName, CompositionAnimati
=> false;
#endif

internal void AddContext(CompositionObject context, string? propertyName)
{
_contextStore.AddContext(context, propertyName);
}

internal void RemoveContext(CompositionObject context, string? propertyName)
{
_contextStore.RemoveContext(context, propertyName);
}

private protected void SetProperty(ref bool field, bool value, [CallerMemberName] string? propertyName = null)
{
if (field == value)
Expand Down Expand Up @@ -344,7 +333,7 @@ private protected void OnCompositionPropertyChanged(CompositionObject? oldValue,
private protected void OnPropertyChanged(string? propertyName, bool isSubPropertyChange)
{
OnPropertyChangedCore(propertyName, isSubPropertyChange);
_contextStore.RaiseChanged();
PropagateChanged();
}

private protected virtual void OnPropertyChangedCore(string? propertyName, bool isSubPropertyChange)
Expand Down
Loading

0 comments on commit ef7b6a1

Please sign in to comment.