Skip to content

Commit

Permalink
feat(composition): More work on Composition effects + working sample
Browse files Browse the repository at this point in the history
  • Loading branch information
ahmed605 committed Mar 2, 2024
1 parent aa7c067 commit 545004e
Show file tree
Hide file tree
Showing 13 changed files with 405 additions and 13 deletions.
11 changes: 9 additions & 2 deletions src/SamplesApp/UITests.Shared/UITests.Shared.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -4562,7 +4562,11 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Media\LoadedImageSurface\LoadedImageSurfaceTests.xaml">
<Page Include="$(MSBuildThisFileDirectory)Windows_UI_Composition\EffectBrushTests.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Media\LoadedImageSurface\LoadedImageSurfaceTests.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
Expand Down Expand Up @@ -8007,7 +8011,10 @@
<Compile Include="$(MSBuildThisFileDirectory)Windows_UI_Composition\MaskBrushTests.xaml.cs">
<DependentUpon>MaskBrushTests.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Media\XamlCompositionBrushBase\XamlCompositionBrushBaseTests.xaml.cs">
<Compile Include="$(MSBuildThisFileDirectory)Windows_UI_Composition\EffectBrushTests.xaml.cs">
<DependentUpon>EffectBrushTests.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Media\XamlCompositionBrushBase\XamlCompositionBrushBaseTests.xaml.cs">
<DependentUpon>XamlCompositionBrushBaseTests.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Media\LoadedImageSurface\LoadedImageSurfaceTests.xaml.cs">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<UserControl
x:Class="UITests.Windows_UI_Composition.EffectBrushTests"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:UITests.Windows_UI_Composition"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">

<Grid>
<Grid x:Name="testGrid" Width="200" Height="200" VerticalAlignment="Top" HorizontalAlignment="Left"/>
</Grid>
</UserControl>
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using Uno.UI.Samples.Controls;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Graphics.Effects;
using Windows.Graphics.Effects.Interop;
using Windows.UI;
using Windows.UI.Composition;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Hosting;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236

namespace UITests.Windows_UI_Composition
{
[Sample("Windows.UI.Composition", Name = "CompositionEffectBrush", Description = "", IsManualTest = true)]
public sealed partial class EffectBrushTests : UserControl
{
public EffectBrushTests()
{
this.InitializeComponent();
this.Loaded += EffectBrushTests_Loaded;
}

private void EffectBrushTests_Loaded(object sender, RoutedEventArgs e)
{
testGrid.Background = new TestBrush();
}

private class TestBrush : Windows.UI.Xaml.Media.XamlCompositionBrushBase
{
protected override void OnConnected()
{
var compositor = Window.Current.Compositor;
var surface = LoadedImageSurface.StartLoadFromUri(new Uri("https://avatars.githubusercontent.com/u/52228309?s=200&v=4"));
surface.LoadCompleted += (s, o) =>
{
if (o.Status == LoadedImageSourceLoadStatus.Success)
{
var brush = compositor.CreateSurfaceBrush(surface);
var effect = new SimpleBlurEffect() { Source = new CompositionEffectSourceParameter("sourceBrush"), BlurAmount = 5.0f };
var factory = compositor.CreateEffectFactory(effect);
var effectBrush = factory.CreateBrush();

effectBrush.SetSourceParameter("sourceBrush", brush);
CompositionBrush = effectBrush;
}
};
}
}

#if WINDOWS_UWP
private interface IGraphicsEffectD2D1Interop { }
#endif

[Guid("1FEB6D69-2FE6-4AC9-8C58-1D7F93E7A6A5")]
private class SimpleBlurEffect : IGraphicsEffect, IGraphicsEffectSource, IGraphicsEffectD2D1Interop
{
private string _name = "SimpleBlurEffect";
private Guid _id = new Guid("1FEB6D69-2FE6-4AC9-8C58-1D7F93E7A6A5");

public string Name
{
get => _name;
set => _name = value;
}

public IGraphicsEffectSource Source { get; set; }

public float BlurAmount { get; set; } = 3.0f;

public uint Optimization { get; set; } // enum

public uint BorderMode { get; set; } // enum

public Guid GetEffectId() => _id;

public void GetNamedPropertyMapping(string name, out uint index, out GraphicsEffectPropertyMapping mapping)
{
switch (name)
{
case "BlurAmount":
{
index = 0;
mapping = GraphicsEffectPropertyMapping.Direct;
break;
}
case "Optimization":
{
index = 1;
mapping = GraphicsEffectPropertyMapping.Direct;
break;
}
case "BorderMode":
{
index = 2;
mapping = GraphicsEffectPropertyMapping.Direct;
break;
}
default:
{
index = 0xFF;
mapping = (GraphicsEffectPropertyMapping)0xFF;
break;
}
}
}

public object GetProperty(uint index)
{
switch (index)
{
case 0:
return BlurAmount;
case 1:
return Optimization;
case 2:
return BorderMode;
default:
return null;
}
}

public uint GetPropertyCount() => 3;
public IGraphicsEffectSource GetSource(uint index) => Source;
public uint GetSourceCount() => 1;
}
}
}
35 changes: 33 additions & 2 deletions src/Uno.UI.Composition/Composition/CompositionEffectBrush.skia.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Windows.Graphics.Effects;
using Windows.Graphics.Effects.Interop;
using System;
using SkiaSharp;

Expand All @@ -22,8 +23,38 @@ private SKImageFilter GenerateEffectFilter(object effect, SKRect bounds)

return SKImageFilter.CreatePaint(paint, new SKImageFilter.CropRect(bounds));
}
else
return null;

return null;
}
case IGraphicsEffectD2D1Interop effectInterop:
{
switch (EffectHelpers.GetEffectType(effectInterop.GetEffectId()))
{
case EffectType.GaussianBlurEffect:
{
if (effectInterop.GetSourceCount() == 1 && effectInterop.GetPropertyCount() == 3 && effectInterop.GetSource(0) is IGraphicsEffectSource source)
{
SKImageFilter sourceFilter = GenerateEffectFilter(source, bounds);
if (sourceFilter is null)
return null;
effectInterop.GetNamedPropertyMapping("BlurAmount", out uint sigmaProp, out _);
effectInterop.GetNamedPropertyMapping("Optimization", out uint optProp, out _);
effectInterop.GetNamedPropertyMapping("BorderMode", out uint borderProp, out _);

// TODO: Implement support for other GraphicsEffectPropertyMapping values than Direct
float sigma = (float)effectInterop.GetProperty(sigmaProp);
_ = (uint)effectInterop.GetProperty(optProp); // TODO
_ = (uint)effectInterop.GetProperty(borderProp); // TODO

return SKImageFilter.CreateBlur(sigma, sigma, sourceFilter, new(bounds));
}

return null;
}
case EffectType.Unsupported:
default:
return null;
}
}
default:
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ internal CompositionEffectFactory(IGraphicsEffect effect, IEnumerable<string> an
if (effect is null)
throw new ArgumentNullException(nameof(effect));

_loadStatus = default;
_extendedError = null;

_effect = effect;
_animatableProperties = animatableProperties;
}
Expand Down
3 changes: 0 additions & 3 deletions src/Uno.UI/Uno.UI.Skia.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,6 @@
<Import Project="..\SourceGenerators\Uno.UI.Tasks\Content\Uno.UI.Tasks.targets" Condition="'$(SkipUnoResourceGeneration)' == '' " />

<ItemGroup>
<UpToDateCheckInput Remove="Graphics\Effects\Interop\EffectHelpers.cs" />
<UpToDateCheckInput Remove="Graphics\Effects\Interop\EffectType.cs" />
<UpToDateCheckInput Remove="Graphics\Effects\Interop\IGraphicsEffectD2D1Interop.cs" />
<UpToDateCheckInput Remove="Graphics\GraphicsEffectPropertyMapping.cs" />
</ItemGroup>

Expand Down
47 changes: 47 additions & 0 deletions src/Uno.UWP/Graphics/Effects/D2D1BlendEffectMode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Windows.Graphics.Effects
{
/// <summary>
/// This enum specifies Direct2D blend modes supported by Composition APIs<br/>
/// Note that Color and Luminosity values are switched to follow the current behavior (which is a bug) on Windows<br/><br/>
/// <remarks>
/// References:<br/>
/// 1- <see href="https://microsoft.github.io/Win2D/WinUI2/html/T_Microsoft_Graphics_Canvas_Effects_BlendEffectMode.htm"/><br/>
/// 2- wuceffects.dll!Windows::UI::Composition::g_pszModeNames
/// </remarks>
/// </summary>
internal enum D2D1BlendEffectMode
{
Multiply = 0,
Screen = 1,
Darken = 2,
Lighten = 3,
//Dissolve = 4, // Note: Composition doesn't support Dissolve yet (as of 10.0.25941.1000)
ColorBurn = 5,
LinearBurn = 6,
DarkerColor = 7,
LighterColor = 8,
ColorDodge = 9,
LinearDodge = 10,
Overlay = 11,
SoftLight = 12,
HardLight = 13,
VividLight = 14,
LinearLight = 15,
PinLight = 16,
HardMix = 17,
Difference = 18,
Exclusion = 19,
Hue = 20, // Note: Composition supports Hue since 19H1, docs are outdated
Saturation = 21, // Note: Composition supports Saturation since 19H1, docs are outdated
Luminosity = 22, // Note: Composition supports Luminosity since 19H1, docs are outdated
Color = 23, // Note: Composition supports Color since 19H1, docs are outdated
Subtract = 24,
Division = 25
}
}
33 changes: 33 additions & 0 deletions src/Uno.UWP/Graphics/Effects/D2D1CompositeMode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Windows.Graphics.Effects
{
/// <summary>
/// This enum specifies Direct2D composite modes supported by Composition APIs<br/><br/>
/// <remarks>
/// References:<br/>
/// 1- <see href="https://microsoft.github.io/Win2D/WinUI2/html/T_Microsoft_Graphics_Canvas_CanvasComposite.htm"/><br/>
/// 2- wuceffects.dll!Windows::UI::Composition::g_pszModeNames_0
/// </remarks>
/// </summary>
internal enum D2D1CompositeMode
{
SourceOver = 0,
DestinationOver = 1,
SourceIn = 2,
DestinationIn = 3,
SourceOut = 4,
DestinationOut = 5,
SourceAtop = 6,
DestinationAtop = 7,
Xor = 8,
Add = 9, // Plus
Copy = 10, // SourceCopy
//BoundedCopy = 11, // Note: Composition doesn't support BoundedCopy yet (as of 10.0.25941.1000)
MaskInvert = 12
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
using Windows.Graphics.Effects;
using System.Runtime.InteropServices;

namespace Windows.UI.Graphics.Effects.Interop
namespace Windows.Graphics.Effects.Interop
{
internal static class EffectHelpers
internal static partial class EffectHelpers
{
public static EffectType GetEffectType(Guid effectId)
{
Expand Down
Loading

0 comments on commit 545004e

Please sign in to comment.