diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml
index d0ba2241c..c25c59157 100644
--- a/.github/workflows/dotnet.yml
+++ b/.github/workflows/dotnet.yml
@@ -316,6 +316,13 @@ jobs:
- name: Publish ComputeSharp.NativeLibrary
run: dotnet publish samples\ComputeSharp.NativeLibrary\ComputeSharp.NativeLibrary.csproj -r win-${{matrix.platform}} -v n
+ # Publish the WinRT component with NativeAOT as well
+ - if: matrix.platform == 'x64'
+ name: Publish ComputeSharp.NativeLibrary.WinRT
+ run: >
+ msbuild samples\ComputeSharp.NativeLibrary.WinRT\ComputeSharp.NativeLibrary.WinRT.csproj /restore -t:publish
+ /p:Configuration=Release /p:Platform=${{matrix.platform}} /p:RuntimeIdentifier=win-${{matrix.platform}}
+
# Download the NuGet packages generated in the previous job and use them
# to build and run the sample project referencing them. This is used as
# a test to ensure the NuGet packages work in a consuming project.
diff --git a/ComputeSharp.sln b/ComputeSharp.sln
index 4797a17ee..af1ec1b28 100644
--- a/ComputeSharp.sln
+++ b/ComputeSharp.sln
@@ -164,7 +164,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "arm64", "arm64", "{B4F6A41C
libs\arm64\WinPixEventRuntime_UAP.dll = libs\arm64\WinPixEventRuntime_UAP.dll
EndProjectSection
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ComputeSharp.NativeLibrary", "samples\ComputeSharp.NativeLibrary\ComputeSharp.NativeLibrary.csproj", "{1A3E20B3-F711-41C0-82EA-3B53A575955C}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ComputeSharp.NativeLibrary", "samples\ComputeSharp.NativeLibrary\ComputeSharp.NativeLibrary.csproj", "{1A3E20B3-F711-41C0-82EA-3B53A575955C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ComputeSharp.NativeLibrary.WinRT", "samples\ComputeSharp.NativeLibrary.WinRT\ComputeSharp.NativeLibrary.WinRT.csproj", "{551EF4FB-F34F-412A-B3E6-E345797560ED}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -454,6 +456,14 @@ Global
{1A3E20B3-F711-41C0-82EA-3B53A575955C}.Release|ARM64.Build.0 = Release|Any CPU
{1A3E20B3-F711-41C0-82EA-3B53A575955C}.Release|x64.ActiveCfg = Release|Any CPU
{1A3E20B3-F711-41C0-82EA-3B53A575955C}.Release|x64.Build.0 = Release|Any CPU
+ {551EF4FB-F34F-412A-B3E6-E345797560ED}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {551EF4FB-F34F-412A-B3E6-E345797560ED}.Debug|ARM64.Build.0 = Debug|ARM64
+ {551EF4FB-F34F-412A-B3E6-E345797560ED}.Debug|x64.ActiveCfg = Debug|x64
+ {551EF4FB-F34F-412A-B3E6-E345797560ED}.Debug|x64.Build.0 = Debug|x64
+ {551EF4FB-F34F-412A-B3E6-E345797560ED}.Release|ARM64.ActiveCfg = Release|ARM64
+ {551EF4FB-F34F-412A-B3E6-E345797560ED}.Release|ARM64.Build.0 = Release|ARM64
+ {551EF4FB-F34F-412A-B3E6-E345797560ED}.Release|x64.ActiveCfg = Release|x64
+ {551EF4FB-F34F-412A-B3E6-E345797560ED}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -492,6 +502,7 @@ Global
{79FD7862-4707-4DE0-8777-3872558E4C1C} = {A5013F9B-92EC-419F-B0B3-3D6B721E7104}
{B4F6A41C-AA9A-4302-92B3-AC64CF2E30F5} = {A5013F9B-92EC-419F-B0B3-3D6B721E7104}
{1A3E20B3-F711-41C0-82EA-3B53A575955C} = {0ED8F632-5E17-46BE-8CC3-B14A82D4AEB1}
+ {551EF4FB-F34F-412A-B3E6-E345797560ED} = {0ED8F632-5E17-46BE-8CC3-B14A82D4AEB1}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4664C5E3-0340-4E22-BCFD-98AAEDF5F2DC}
diff --git a/samples/ComputeSharp.NativeLibrary.WinRT/ComputeSharp.NativeLibrary.WinRT.csproj b/samples/ComputeSharp.NativeLibrary.WinRT/ComputeSharp.NativeLibrary.WinRT.csproj
new file mode 100644
index 000000000..cb6f39da5
--- /dev/null
+++ b/samples/ComputeSharp.NativeLibrary.WinRT/ComputeSharp.NativeLibrary.WinRT.csproj
@@ -0,0 +1,56 @@
+
+
+ net8.0-windows10.0.22621.0
+ 10.0.22621.35-preview
+ x64;ARM64
+ win-x64;win-arm64
+
+
+
+ true
+
+
+ ComputeSharp.NativeLibrary
+
+
+ false
+ true
+ false
+ false
+ false
+ false
+
+
+ $(NoWarn);LNK4104
+
+
+
+
+ true
+ true
+ true
+ Size
+ false
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/ComputeSharp.NativeLibrary.WinRT/HelloWorldEffect.cs b/samples/ComputeSharp.NativeLibrary.WinRT/HelloWorldEffect.cs
new file mode 100644
index 000000000..5927c4f6b
--- /dev/null
+++ b/samples/ComputeSharp.NativeLibrary.WinRT/HelloWorldEffect.cs
@@ -0,0 +1,82 @@
+using ComputeSharp.D2D1;
+using ComputeSharp.D2D1.WinUI;
+using Windows.Foundation;
+
+namespace ComputeSharp.NativeLibrary;
+
+///
+/// A hello world effect that displays a color gradient.
+///
+public sealed partial class HelloWorldEffect : CanvasEffect
+{
+ ///
+ /// The node in use.
+ ///
+ private static readonly CanvasEffectNode> EffectNode = new();
+
+ ///
+ private float time;
+
+ ///
+ private Rect dispatchArea;
+
+ ///
+ /// Gets or sets the current time since the start of the application.
+ ///
+ public float Time
+ {
+ get => this.time;
+ set => SetAndInvalidateEffectGraph(ref this.time, value);
+ }
+
+ ///
+ /// Gets or sets the dispatch area for the current output.
+ ///
+ public Rect DispatchArea
+ {
+ get => this.dispatchArea;
+ set => SetAndInvalidateEffectGraph(ref this.dispatchArea, value);
+ }
+
+ ///
+ protected override void BuildEffectGraph(CanvasEffectGraph effectGraph)
+ {
+ effectGraph.RegisterOutputNode(EffectNode, new PixelShaderEffect());
+ }
+
+ ///
+ protected override void ConfigureEffectGraph(CanvasEffectGraph effectGraph)
+ {
+ effectGraph.GetNode(EffectNode).ConstantBuffer = new Shader(
+ time: this.time,
+ dispatchSize: new int2(
+ x: (int)double.Round(this.dispatchArea.Width),
+ y: (int)double.Round(this.dispatchArea.Height)));
+ }
+
+ ///
+ /// A hello world effect that displays a color gradient.
+ ///
+ /// The current time since the start of the application.
+ /// The dispatch size for the current output.
+ [D2DEffectDisplayName(nameof(HelloWorldEffect))]
+ [D2DEffectDescription("A hello world effect that displays a color gradient.")]
+ [D2DEffectCategory("Render")]
+ [D2DEffectAuthor("ComputeSharp.D2D1")]
+ [D2DInputCount(0)]
+ [D2DRequiresScenePosition]
+ [D2DShaderProfile(D2D1ShaderProfile.PixelShader50)]
+ [D2DGeneratedPixelShaderDescriptor]
+ internal readonly partial struct Shader(float time, int2 dispatchSize) : ID2D1PixelShader
+ {
+ ///
+ public float4 Execute()
+ {
+ int2 xy = (int2)D2D.GetScenePosition().XY;
+ float2 uv = xy / (float2)dispatchSize;
+ float3 color = 0.5f + (0.5f * Hlsl.Cos(time + new float3(uv, uv.X) + new float3(0, 2, 4)));
+
+ return new(color, 1f);
+ }
+ }
+}